xdg.systemDirs: init module (#1797)

There is a need to manage XDG Base Directory system directory
environment variables in Home Manager modules. There is an existing
mechanism in `targets.genericLinux.extraXdgDataDirs', but this does not
apply to NixOS systems.

Furthermore, it is important that `XDG_CONFIG_DIRS' and `XDG_DATA_DIRS'
are set in both login shells (to support getty and SSH sessions) as well
as the systemd user manager (to propagate them to user services and
desktop environments).

The first need is addressed by adding the `xdg.systemDirs' module, which
configures lists of directory names for both `config' and `data'
directories. These are then set in
`$XDG_CONFIG_DIR/environment.d/10-home-manager.conf' and picked up by
the systemd user manager.

To make these, and other variables set in
`systemd.user.sessionVariables', available in login shells, an
additional step is added to `etc/profile.d/hm-session-vars.sh' which
exports the result of
`user-environment-generators/30-systemd-environment-d-generator' which
is shipped with systemd. The effect of this generator is to print
variables set on the systemd user manager such that shells can import
these into their environment.
This commit is contained in:
Tad Fisher 2021-05-10 17:14:42 -07:00 committed by GitHub
parent 3b799f6ea4
commit 23769994e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 169 additions and 46 deletions

3
.github/CODEOWNERS vendored
View file

@ -34,6 +34,9 @@
/modules/misc/xdg-user-dirs.nix @pacien /modules/misc/xdg-user-dirs.nix @pacien
/modules/misc/xdg-system-dirs.nix @tadfisher
/tests/modules/misc/xdg/system-dirs.nix @tadfisher
/modules/programs/aria2.nix @JustinLovinger /modules/programs/aria2.nix @JustinLovinger
/modules/programs/autojump.nix @evanjs /modules/programs/autojump.nix @evanjs

View file

@ -1980,6 +1980,26 @@ in
A new module is available: 'programs.nix-index'. A new module is available: 'programs.nix-index'.
''; '';
} }
{
time = "2021-05-10T18:50:07+00:00";
message = ''
A new module is available: 'xdg.systemDirs'. Options are:
- xdg.systemDirs.config
Extra directory names to add to $XDG_CONFIG_DIRS in the user
session.
- xdg.systemDirs.data
Extra directory names to add to $XDG_DATA_DIRS in the user
session.
These variables are visible in both systemd user services and
login shells.
'';
}
]; ];
}; };
} }

View file

@ -0,0 +1,49 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.xdg.systemDirs;
configDirs = concatStringsSep ":" cfg.config;
dataDirs = concatStringsSep ":" cfg.data;
in {
meta.maintainers = with maintainers; [ tadfisher ];
options.xdg.systemDirs = {
config = mkOption {
type = types.listOf types.str;
default = [ ];
example = literalExample ''[ "/etc/xdg" ]'';
description = ''
Directory names to add to <envar>XDG_CONFIG_DIRS</envar>
in the user session.
'';
};
data = mkOption {
type = types.listOf types.str;
default = [ ];
example = literalExample ''[ "/usr/share" "/usr/local/share" ]'';
description = ''
Directory names to add to <envar>XDG_DATA_DIRS</envar>
in the user session.
'';
};
};
config = mkMerge [
(mkIf (cfg.config != [ ]) {
systemd.user.sessionVariables.XDG_CONFIG_DIRS =
"${configDirs}\${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}";
})
(mkIf (cfg.data != [ ]) {
systemd.user.sessionVariables.XDG_DATA_DIRS =
"${dataDirs}\${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}";
})
];
}

View file

@ -40,6 +40,7 @@ let
(loadModule ./misc/tmpfiles.nix { condition = hostPlatform.isLinux; }) (loadModule ./misc/tmpfiles.nix { condition = hostPlatform.isLinux; })
(loadModule ./misc/version.nix { }) (loadModule ./misc/version.nix { })
(loadModule ./misc/vte.nix { }) (loadModule ./misc/vte.nix { })
(loadModule ./misc/xdg-system-dirs.nix { condition = hostPlatform.isLinux; })
(loadModule ./misc/xdg-mime.nix { condition = hostPlatform.isLinux; }) (loadModule ./misc/xdg-mime.nix { condition = hostPlatform.isLinux; })
(loadModule ./misc/xdg-mime-apps.nix { condition = hostPlatform.isLinux; }) (loadModule ./misc/xdg-mime-apps.nix { condition = hostPlatform.isLinux; })
(loadModule ./misc/xdg-user-dirs.nix { condition = hostPlatform.isLinux; }) (loadModule ./misc/xdg-user-dirs.nix { condition = hostPlatform.isLinux; })

View file

@ -333,6 +333,11 @@ in
unset systemdStatus unset systemdStatus
'' ''
); );
# Export environment variables in systemd.user.sessionVariables to login shells.
home.sessionVariablesExtra = optionalString (cfg.sessionVariables != {}) ''
export $(${pkgs.systemd}/lib/systemd/user-environment-generators/30-systemd-environment-d-generator)
'';
}) })
]; ];
} }

View file

@ -4,9 +4,19 @@ with lib;
let let
cfg = config.targets.genericLinux;
profileDirectory = config.home.profileDirectory; profileDirectory = config.home.profileDirectory;
in { in {
imports = [
(mkRenamedOptionModule [ "targets" "genericLinux" "extraXdgDataDirs" ] [
"xdg"
"systemDirs"
"data"
])
];
options.targets.genericLinux = { options.targets.genericLinux = {
enable = mkEnableOption "" // { enable = mkEnableOption "" // {
description = '' description = ''
@ -14,39 +24,20 @@ in {
GNU/Linux distributions other than NixOS. GNU/Linux distributions other than NixOS.
''; '';
}; };
extraXdgDataDirs = mkOption {
type = types.listOf types.str;
default = [ ];
example = [ "/usr/share" "/usr/local/share" ];
description = ''
List of directory names to add to <envar>XDG_DATA_DIRS</envar>.
'';
};
}; };
config = mkIf config.targets.genericLinux.enable { config = mkIf cfg.enable {
home.sessionVariables = let xdg.systemDirs.data = [
profiles = # Nix profiles
[ "\${NIX_STATE_DIR:-/nix/var/nix}/profiles/default" profileDirectory ]; "\${NIX_STATE_DIR:-/nix/var/nix}/profiles/default/share"
dataDirs = concatStringsSep ":" "${profileDirectory}/share"
(map (profile: "${profile}/share") profiles
++ config.targets.genericLinux.extraXdgDataDirs);
# https://github.com/archlinux/svntogit-packages/blob/packages/ncurses/trunk/PKGBUILD # Distribution-specific
# https://salsa.debian.org/debian/ncurses/-/blob/master/debian/rules "/usr/share/ubuntu"
# https://src.fedoraproject.org/rpms/ncurses/blob/main/f/ncurses.spec "/usr/local/share"
# https://gitweb.gentoo.org/repo/gentoo.git/tree/sys-libs/ncurses/ncurses-6.2-r1.ebuild "/usr/share"
distroTerminfoDirs = concatStringsSep ":" [ "/var/lib/snapd/desktop"
"/etc/terminfo" # debian, fedora, gentoo
"/lib/terminfo" # debian
"/usr/share/terminfo" # package default, all distros
]; ];
in {
XDG_DATA_DIRS = "${dataDirs}\${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS";
TERMINFO_DIRS =
"${profileDirectory}/share/terminfo:$TERMINFO_DIRS\${TERMINFO_DIRS:+:}${distroTerminfoDirs}";
};
home.sessionVariablesExtra = '' home.sessionVariablesExtra = ''
. "${pkgs.nix}/etc/profile.d/nix.sh" . "${pkgs.nix}/etc/profile.d/nix.sh"
@ -62,8 +53,20 @@ in {
. "${profileDirectory}/etc/profile.d/hm-session-vars.sh" . "${profileDirectory}/etc/profile.d/hm-session-vars.sh"
''; '';
systemd.user.sessionVariables = { systemd.user.sessionVariables = let
# https://github.com/archlinux/svntogit-packages/blob/packages/ncurses/trunk/PKGBUILD
# https://salsa.debian.org/debian/ncurses/-/blob/master/debian/rules
# https://src.fedoraproject.org/rpms/ncurses/blob/main/f/ncurses.spec
# https://gitweb.gentoo.org/repo/gentoo.git/tree/sys-libs/ncurses/ncurses-6.2-r1.ebuild
distroTerminfoDirs = concatStringsSep ":" [
"/etc/terminfo" # debian, fedora, gentoo
"/lib/terminfo" # debian
"/usr/share/terminfo" # package default, all distros
];
in {
NIX_PATH = "$HOME/.nix-defexpr/channels\${NIX_PATH:+:}$NIX_PATH"; NIX_PATH = "$HOME/.nix-defexpr/channels\${NIX_PATH:+:}$NIX_PATH";
TERMINFO_DIRS =
"${profileDirectory}/share/terminfo:$TERMINFO_DIRS\${TERMINFO_DIRS:+:}${distroTerminfoDirs}";
}; };
}; };
} }

View file

@ -15,6 +15,7 @@ let
export XDG_CACHE_HOME="/home/hm-user/.cache" export XDG_CACHE_HOME="/home/hm-user/.cache"
export XDG_CONFIG_HOME="/home/hm-user/.config" export XDG_CONFIG_HOME="/home/hm-user/.config"
export XDG_DATA_HOME="/home/hm-user/.local/share" export XDG_DATA_HOME="/home/hm-user/.local/share"
export $(${pkgs.systemd}/lib/systemd/user-environment-generators/30-systemd-environment-d-generator)
''; '';
darwinExpected = '' darwinExpected = ''

View file

@ -1,4 +1,5 @@
{ {
xdg-mime-apps-basics = ./mime-apps-basics.nix; xdg-mime-apps-basics = ./mime-apps-basics.nix;
xdg-file-attr-names = ./file-attr-names.nix; xdg-file-attr-names = ./file-attr-names.nix;
xdg-system-dirs = ./system-dirs.nix;
} }

View file

@ -0,0 +1,25 @@
{ config, lib, pkgs, ... }:
{
config = {
xdg.systemDirs.config = [ "/etc/xdg" "/foo/bar" ];
xdg.systemDirs.data = [ "/usr/local/share" "/usr/share" "/baz/quux" ];
nmt.script = ''
envFile=home-files/.config/environment.d/10-home-manager.conf
assertFileExists $envFile
assertFileContent $envFile ${
pkgs.writeText "expected" ''
LOCALE_ARCHIVE_2_27=${pkgs.glibcLocales}/lib/locale/locale-archive
XDG_CONFIG_DIRS=/etc/xdg:/foo/bar''${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}
XDG_DATA_DIRS=/usr/local/share:/usr/share:/baz/quux''${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}
''
}
sessionVarsFile=home-path/etc/profile.d/hm-session-vars.sh
assertFileExists $sessionVarsFile
assertFileContains $sessionVarsFile \
'export $(${pkgs.systemd}/lib/systemd/user-environment-generators/30-systemd-environment-d-generator)'
'';
};
}

View file

@ -15,6 +15,11 @@
V_int=1 V_int=1
V_str=2 V_str=2
''} ''}
sessionVarsFile=home-path/etc/profile.d/hm-session-vars.sh
assertFileExists $sessionVarsFile
assertFileContains $sessionVarsFile \
'export $(${pkgs.systemd}/lib/systemd/user-environment-generators/30-systemd-environment-d-generator)'
''; '';
}; };
} }

View file

@ -2,26 +2,36 @@
with lib; with lib;
{ let
expectedXdgDataDirs = concatStringsSep ":" [
"\${NIX_STATE_DIR:-/nix/var/nix}/profiles/default/share"
"/home/hm-user/.nix-profile/share"
"/usr/share/ubuntu"
"/usr/local/share"
"/usr/share"
"/var/lib/snapd/desktop"
"/foo"
];
in {
config = { config = {
targets.genericLinux = { targets.genericLinux.enable = true;
enable = true;
extraXdgDataDirs = [ "/foo" ]; xdg.systemDirs.data = [ "/foo" ];
};
nmt.script = '' nmt.script = ''
assertFileExists home-path/etc/profile.d/hm-session-vars.sh envFile=home-files/.config/environment.d/10-home-manager.conf
assertFileExists $envFile
assertFileContains $envFile \
'XDG_DATA_DIRS=${expectedXdgDataDirs}''${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}'
assertFileContains $envFile \
'TERMINFO_DIRS=/home/hm-user/.nix-profile/share/terminfo:$TERMINFO_DIRS''${TERMINFO_DIRS:+:}/etc/terminfo:/lib/terminfo:/usr/share/terminfo'
assertFileContains \ sessionVarsFile=home-path/etc/profile.d/hm-session-vars.sh
home-path/etc/profile.d/hm-session-vars.sh \ assertFileExists $sessionVarsFile
'export XDG_DATA_DIRS="''${NIX_STATE_DIR:-/nix/var/nix}/profiles/default/share:/home/hm-user/.nix-profile/share:/foo''${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS"' assertFileContains $sessionVarsFile \
assertFileContains \
home-path/etc/profile.d/hm-session-vars.sh \
'. "${pkgs.nix}/etc/profile.d/nix.sh"' '. "${pkgs.nix}/etc/profile.d/nix.sh"'
assertFileContains \
home-path/etc/profile.d/hm-session-vars.sh \
'export TERMINFO_DIRS="/home/hm-user/.nix-profile/share/terminfo:$TERMINFO_DIRS''${TERMINFO_DIRS:+:}/etc/terminfo:/lib/terminfo:/usr/share/terminfo"'
assertFileContains \ assertFileContains \
home-path/etc/profile.d/hm-session-vars.sh \ home-path/etc/profile.d/hm-session-vars.sh \
'export TERM="$TERM"' 'export TERM="$TERM"'