diff --git a/modules/home-environment.nix b/modules/home-environment.nix index bc131015..4f4904c7 100644 --- a/modules/home-environment.nix +++ b/modules/home-environment.nix @@ -618,7 +618,7 @@ in home.profileDirectory = if config.submoduleSupport.enable && config.submoduleSupport.externalPackageInstall then "/etc/profiles/per-user/${cfg.username}" - else if config.nix.enable && (config.nix.settings.use-xdg-base-directories or false) then + else if config.nix.useXdg then "${config.xdg.stateHome}/nix/profile" else cfg.homeDirectory + "/.nix-profile"; diff --git a/modules/misc/nix.nix b/modules/misc/nix.nix index c07e0330..11b22296 100644 --- a/modules/misc/nix.nix +++ b/modules/misc/nix.nix @@ -1,6 +1,7 @@ { config, lib, + osConfig, pkgs, ... }: @@ -21,6 +22,7 @@ let isList isString literalExpression + literalMD mapAttrsToList mkDefault mkEnableOption @@ -41,7 +43,7 @@ let nixPath = concatStringsSep ":" cfg.nixPath; - useXdg = config.nix.enable && (config.nix.settings.use-xdg-base-directories or false); + inherit (config.nix) useXdg; defexprDir = if useXdg then "${config.xdg.stateHome}/nix/defexpr" @@ -296,6 +298,30 @@ in ''; }; + assumeXdg = mkOption { + type = types.bool; + default = false; + description = '' + Whether Home Manager should assume that Nix is configured to use XDG + base directories. Note that this doesn't change the behavior of Nix. To + do that, set nix.settings.use-xdg-base-directories instead. This option + is intended for settings in which use-xdg-base-directories is set + globally or nix.conf is unmanaged by Home Manager. + ''; + }; + + useXdg = mkOption { + type = types.bool; + visible = false; + readOnly = true; + defaultText = literalMD '' + In descending priority: + * `true` if `nix.assumeXdg` is `true` + * `nix.settings.use-xdg-base-directories` if it is set and `nix.enable` is `true` + * `osConfig.nix.settings.use-xdg-base-directories` if it is set and `osConfig.nix.enable` is `true` + ''; + }; + extraOptions = mkOption { type = types.lines; default = ""; @@ -326,39 +352,69 @@ in }; }; - config = mkIf cfg.enable (mkMerge [ - (mkIf (cfg.nixPath != [ ] && !cfg.keepOldNixPath) { - home.sessionVariables.NIX_PATH = "${nixPath}"; - }) + config = mkMerge [ + { + nix.useXdg = + let + # Helper that checks if use-xdg-base-directories is in effect for the + # given Nix configuration, falling back to a given default value if + # it is undefined or the configuration is not enabled. + checkNixXdg = def: cfg: if cfg.enable then cfg.settings.use-xdg-base-directories or def else def; - (mkIf (cfg.nixPath != [ ] && cfg.keepOldNixPath) { - home.sessionVariables.NIX_PATH = "${nixPath}\${NIX_PATH:+:$NIX_PATH}"; - }) + # Whether the OS configuration indicates that XDG directories should + # be used. + osUseXdg = checkNixXdg false osConfig.nix or { enable = false; }; - (lib.mkIf (cfg.channels != { }) { - nix.nixPath = [ channelPath ]; - home.file."${channelPath}".source = channelsDrv; - }) + # Whether the user configuration indicates that XDG directories + # should be used, falling back to the OS configuration if not + # specified. + hmUseXdg = checkNixXdg osUseXdg cfg; + in + cfg.assumeXdg || hmUseXdg; - (mkIf (cfg.registry != { }) { - xdg.configFile."nix/registry.json".source = jsonFormat.generate "registry.json" { - version = cfg.registryVersion; - flakes = mapAttrsToList (n: v: { inherit (v) from to exact; }) cfg.registry; - }; - }) - - (mkIf (cfg.settings != { } || cfg.extraOptions != "") { assertions = [ { - assertion = cfg.package != null; + assertion = !(cfg.assumeXdg && cfg.enable && cfg.settings ? use-xdg-base-directories); message = '' - A corresponding Nix package must be specified via `nix.package` for generating - nix.conf. + `nix.assumeXdg` should not be set if `nix.settings.use-xdg-base-directories` is. ''; } ]; + } + (mkIf cfg.enable (mkMerge [ + (mkIf (cfg.nixPath != [ ] && !cfg.keepOldNixPath) { + home.sessionVariables.NIX_PATH = "${nixPath}"; + }) - xdg.configFile."nix/nix.conf".source = nixConf; - }) - ]); + (mkIf (cfg.nixPath != [ ] && cfg.keepOldNixPath) { + home.sessionVariables.NIX_PATH = "${nixPath}\${NIX_PATH:+:$NIX_PATH}"; + }) + + (lib.mkIf (cfg.channels != { }) { + nix.nixPath = [ channelPath ]; + home.file."${channelPath}".source = channelsDrv; + }) + + (mkIf (cfg.registry != { }) { + xdg.configFile."nix/registry.json".source = jsonFormat.generate "registry.json" { + version = cfg.registryVersion; + flakes = mapAttrsToList (n: v: { inherit (v) from to exact; }) cfg.registry; + }; + }) + + (mkIf (cfg.settings != { } || cfg.extraOptions != "") { + assertions = [ + { + assertion = cfg.package != null; + message = '' + A corresponding Nix package must be specified via `nix.package` for generating + nix.conf. + ''; + } + ]; + + xdg.configFile."nix/nix.conf".source = nixConf; + }) + ])) + ]; } diff --git a/modules/targets/generic-linux.nix b/modules/targets/generic-linux.nix index 31529fc2..6ebf5d9c 100644 --- a/modules/targets/generic-linux.nix +++ b/modules/targets/generic-linux.nix @@ -112,7 +112,7 @@ in in { NIX_PATH = - if config.nix.enable && (config.nix.settings.use-xdg-base-directories or false) then + if config.nix.useXdg then "${config.xdg.stateHome}/nix/defexpr/channels\${NIX_PATH:+:}$NIX_PATH" else "$HOME/.nix-defexpr/channels\${NIX_PATH:+:}$NIX_PATH"; diff --git a/tests/modules/misc/nix/default.nix b/tests/modules/misc/nix/default.nix index 4c8822bf..50a8b1e3 100644 --- a/tests/modules/misc/nix/default.nix +++ b/tests/modules/misc/nix/default.nix @@ -5,4 +5,5 @@ nix-keep-old-nix-path = ./keep-old-nix-path.nix; nix-example-channels = ./example-channels.nix; nix-example-channels-xdg = ./example-channels-xdg.nix; + nix-use-xdg = ./use-xdg.nix; } diff --git a/tests/modules/misc/nix/use-xdg.nix b/tests/modules/misc/nix/use-xdg.nix new file mode 100644 index 00000000..f4d4b189 --- /dev/null +++ b/tests/modules/misc/nix/use-xdg.nix @@ -0,0 +1,92 @@ +{ lib, pkgs, ... }: +let + nixosLib = import /${pkgs.path}/nixos/lib { inherit lib; }; + getUseXdg = + osNix: userNix: + (nixosLib.evalTest { + hostPkgs = pkgs; + nodes.machine.imports = [ + ../../../../nixos + { + nix = osNix; + home-manager.users.user = { + home.stateVersion = "26.05"; + nix = userNix; + }; + } + ]; + }).config.nodes.machine.home-manager.users.user.nix.useXdg; +in +{ + nmt.script = + # Defaults to false + assert !getUseXdg { } { }; + + # Test OS config + assert !getUseXdg { enable = true; } { }; + assert + !getUseXdg { + enable = false; + settings.use-xdg-base-directories = true; + } { }; + assert getUseXdg { + enable = true; + settings.use-xdg-base-directories = true; + } { }; + + # Test user config + assert !getUseXdg { } { enable = true; }; + assert + !getUseXdg { } { + enable = false; + settings.use-xdg-base-directories = true; + }; + assert getUseXdg { } { + enable = true; + settings.use-xdg-base-directories = true; + }; + + # Fallback to OS config if user config is unset + assert getUseXdg + { + enable = true; + settings.use-xdg-base-directories = true; + } + { + enable = true; + }; + + # But user config takes precedence + assert + !getUseXdg + { + enable = true; + settings.use-xdg-base-directories = true; + } + { + enable = true; + settings.use-xdg-base-directories = false; + }; + assert getUseXdg + { + enable = true; + settings.use-xdg-base-directories = false; + } + { + enable = true; + settings.use-xdg-base-directories = true; + }; + + # assumeXdg also takes precedence + assert getUseXdg { } { assumeXdg = true; }; + assert getUseXdg + { + enable = true; + settings.use-xdg-base-directories = false; + } + { + enable = false; + assumeXdg = true; + }; + ""; +} diff --git a/tests/modules/targets-linux/default.nix b/tests/modules/targets-linux/default.nix index 24786f8d..5ae5fd0f 100644 --- a/tests/modules/targets-linux/default.nix +++ b/tests/modules/targets-linux/default.nix @@ -3,4 +3,5 @@ targets-generic-linux-gpu-basic = ./generic-linux-gpu/basic-enable.nix; targets-generic-linux-gpu-setup-contents = ./generic-linux-gpu/setup-package-contents.nix; targets-generic-linux-gpu-nvidia = ./generic-linux-gpu/nvidia-enabled.nix; + targets-generic-linux-xdg = ./generic-linux-xdg.nix; } diff --git a/tests/modules/targets-linux/generic-linux-xdg.nix b/tests/modules/targets-linux/generic-linux-xdg.nix new file mode 100644 index 00000000..fa462b86 --- /dev/null +++ b/tests/modules/targets-linux/generic-linux-xdg.nix @@ -0,0 +1,39 @@ +{ lib, pkgs, ... }: +let + expectedXdgDataDirs = lib.concatStringsSep ":" [ + "\${NIX_STATE_DIR:-/nix/var/nix}/profiles/default/share" + "/home/hm-user/.local/state/nix/profile/share" + "/usr/share/ubuntu" + "/usr/local/share" + "/usr/share" + "/var/lib/snapd/desktop" + "/foo" + ]; +in +{ + config = { + targets.genericLinux.enable = true; + + xdg.systemDirs.data = [ "/foo" ]; + + nix.assumeXdg = true; + + nmt.script = '' + 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/.local/state/nix/profile/share/terminfo:$TERMINFO_DIRS''${TERMINFO_DIRS:+:}/etc/terminfo:/lib/terminfo:/usr/share/terminfo' + + 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 TERM="$TERM"' + ''; + }; +}