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"'