From 23769994e8f7b212d9a257799173b120ed87736b Mon Sep 17 00:00:00 2001
From: Tad Fisher <129148+tadfisher@users.noreply.github.com>
Date: Mon, 10 May 2021 17:14:42 -0700
Subject: [PATCH] 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.
---
.github/CODEOWNERS | 3 +
modules/misc/news.nix | 22 ++++++-
modules/misc/xdg-system-dirs.nix | 49 ++++++++++++++
modules/modules.nix | 1 +
modules/systemd.nix | 5 ++
modules/targets/generic-linux.nix | 65 ++++++++++---------
.../home-environment/session-variables.nix | 1 +
tests/modules/misc/xdg/default.nix | 1 +
tests/modules/misc/xdg/system-dirs.nix | 25 +++++++
tests/modules/systemd/session-variables.nix | 5 ++
tests/modules/targets-linux/generic-linux.nix | 38 +++++++----
11 files changed, 169 insertions(+), 46 deletions(-)
create mode 100644 modules/misc/xdg-system-dirs.nix
create mode 100644 tests/modules/misc/xdg/system-dirs.nix
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 0a8cb5e5..6b0f08df 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -34,6 +34,9 @@
/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/autojump.nix @evanjs
diff --git a/modules/misc/news.nix b/modules/misc/news.nix
index 6234dc7b..daa86665 100644
--- a/modules/misc/news.nix
+++ b/modules/misc/news.nix
@@ -1965,7 +1965,7 @@ in
The option 'services.sxhkd.extraPath' has been deprecated.
'';
}
-
+
{
time = "2021-05-06T20:47:37+00:00";
condition = hostPlatform.isLinux;
@@ -1980,6 +1980,26 @@ in
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.
+ '';
+ }
];
};
}
diff --git a/modules/misc/xdg-system-dirs.nix b/modules/misc/xdg-system-dirs.nix
new file mode 100644
index 00000000..d3fad015
--- /dev/null
+++ b/modules/misc/xdg-system-dirs.nix
@@ -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 XDG_CONFIG_DIRS
+ 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 XDG_DATA_DIRS
+ 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}";
+ })
+ ];
+}
diff --git a/modules/modules.nix b/modules/modules.nix
index 6a6f4f08..573764b3 100644
--- a/modules/modules.nix
+++ b/modules/modules.nix
@@ -40,6 +40,7 @@ let
(loadModule ./misc/tmpfiles.nix { condition = hostPlatform.isLinux; })
(loadModule ./misc/version.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-apps.nix { condition = hostPlatform.isLinux; })
(loadModule ./misc/xdg-user-dirs.nix { condition = hostPlatform.isLinux; })
diff --git a/modules/systemd.nix b/modules/systemd.nix
index e1261b7b..7c03b562 100644
--- a/modules/systemd.nix
+++ b/modules/systemd.nix
@@ -333,6 +333,11 @@ in
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)
+ '';
})
];
}
diff --git a/modules/targets/generic-linux.nix b/modules/targets/generic-linux.nix
index a6486d73..6e17bd28 100644
--- a/modules/targets/generic-linux.nix
+++ b/modules/targets/generic-linux.nix
@@ -4,9 +4,19 @@ with lib;
let
+ cfg = config.targets.genericLinux;
+
profileDirectory = config.home.profileDirectory;
in {
+ imports = [
+ (mkRenamedOptionModule [ "targets" "genericLinux" "extraXdgDataDirs" ] [
+ "xdg"
+ "systemDirs"
+ "data"
+ ])
+ ];
+
options.targets.genericLinux = {
enable = mkEnableOption "" // {
description = ''
@@ -14,39 +24,20 @@ in {
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 XDG_DATA_DIRS.
- '';
- };
};
- config = mkIf config.targets.genericLinux.enable {
- home.sessionVariables = let
- profiles =
- [ "\${NIX_STATE_DIR:-/nix/var/nix}/profiles/default" profileDirectory ];
- dataDirs = concatStringsSep ":"
- (map (profile: "${profile}/share") profiles
- ++ config.targets.genericLinux.extraXdgDataDirs);
+ config = mkIf cfg.enable {
+ xdg.systemDirs.data = [
+ # Nix profiles
+ "\${NIX_STATE_DIR:-/nix/var/nix}/profiles/default/share"
+ "${profileDirectory}/share"
- # 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 {
- XDG_DATA_DIRS = "${dataDirs}\${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS";
- TERMINFO_DIRS =
- "${profileDirectory}/share/terminfo:$TERMINFO_DIRS\${TERMINFO_DIRS:+:}${distroTerminfoDirs}";
- };
+ # Distribution-specific
+ "/usr/share/ubuntu"
+ "/usr/local/share"
+ "/usr/share"
+ "/var/lib/snapd/desktop"
+ ];
home.sessionVariablesExtra = ''
. "${pkgs.nix}/etc/profile.d/nix.sh"
@@ -62,8 +53,20 @@ in {
. "${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";
+ TERMINFO_DIRS =
+ "${profileDirectory}/share/terminfo:$TERMINFO_DIRS\${TERMINFO_DIRS:+:}${distroTerminfoDirs}";
};
};
}
diff --git a/tests/modules/home-environment/session-variables.nix b/tests/modules/home-environment/session-variables.nix
index d939c05e..5f52b620 100644
--- a/tests/modules/home-environment/session-variables.nix
+++ b/tests/modules/home-environment/session-variables.nix
@@ -15,6 +15,7 @@ let
export XDG_CACHE_HOME="/home/hm-user/.cache"
export XDG_CONFIG_HOME="/home/hm-user/.config"
export XDG_DATA_HOME="/home/hm-user/.local/share"
+ export $(${pkgs.systemd}/lib/systemd/user-environment-generators/30-systemd-environment-d-generator)
'';
darwinExpected = ''
diff --git a/tests/modules/misc/xdg/default.nix b/tests/modules/misc/xdg/default.nix
index 813a2520..45610154 100644
--- a/tests/modules/misc/xdg/default.nix
+++ b/tests/modules/misc/xdg/default.nix
@@ -1,4 +1,5 @@
{
xdg-mime-apps-basics = ./mime-apps-basics.nix;
xdg-file-attr-names = ./file-attr-names.nix;
+ xdg-system-dirs = ./system-dirs.nix;
}
diff --git a/tests/modules/misc/xdg/system-dirs.nix b/tests/modules/misc/xdg/system-dirs.nix
new file mode 100644
index 00000000..d2913b23
--- /dev/null
+++ b/tests/modules/misc/xdg/system-dirs.nix
@@ -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)'
+ '';
+ };
+}
diff --git a/tests/modules/systemd/session-variables.nix b/tests/modules/systemd/session-variables.nix
index 59d1a4d3..21d96d44 100644
--- a/tests/modules/systemd/session-variables.nix
+++ b/tests/modules/systemd/session-variables.nix
@@ -15,6 +15,11 @@
V_int=1
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)'
'';
};
}
diff --git a/tests/modules/targets-linux/generic-linux.nix b/tests/modules/targets-linux/generic-linux.nix
index 530137cf..88cec8a0 100644
--- a/tests/modules/targets-linux/generic-linux.nix
+++ b/tests/modules/targets-linux/generic-linux.nix
@@ -2,26 +2,36 @@
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 = {
- targets.genericLinux = {
- enable = true;
- extraXdgDataDirs = [ "/foo" ];
- };
+ targets.genericLinux.enable = true;
+
+ xdg.systemDirs.data = [ "/foo" ];
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 \
- home-path/etc/profile.d/hm-session-vars.sh \
- '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 \
- home-path/etc/profile.d/hm-session-vars.sh \
+ sessionVarsFile=home-path/etc/profile.d/hm-session-vars.sh
+ assertFileExists $sessionVarsFile
+ assertFileContains $sessionVarsFile \
'. "${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 \
home-path/etc/profile.d/hm-session-vars.sh \
'export TERM="$TERM"'