diff --git a/README.md b/README.md index f83af336..7c7d4b12 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,24 @@ Currently the easiest way to install Home Manager is as follows: Home Manager should now be active and available in your user environment. +5. If you do not plan on having Home Manager manage your shell + configuration then you must source the + + ``` + "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh" + ``` + + file in your shell configuration. Unfortunately, we currently only + support POSIX.2-like shells such as [Bash][] or [Z shell][]. + + For example, if you use Bash then add + + ```bash + . "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh" + ``` + + to your `~/.profile` file. + Note, because the `HM_PATH` variable above points to the live Home Manager repository you will automatically get updates whenever you build a new generation. If you dislike automatic updates then perform @@ -240,8 +258,10 @@ in your system configuration and in your Home Manager configuration. +[Bash]: https://www.gnu.org/software/bash/ [Nix]: https://nixos.org/nix/ [NixOS]: https://nixos.org/ [Nixpkgs]: https://nixos.org/nixpkgs/ [nixAllowedUsers]: https://nixos.org/nix/manual/#conf-allowed-users [nixosAllowedUsers]: https://nixos.org/nixos/manual/options.html#opt-nix.allowedUsers +[Z shell]: http://zsh.sourceforge.net/ diff --git a/modules/home-environment.nix b/modules/home-environment.nix index f2936415..197e9dc5 100644 --- a/modules/home-environment.nix +++ b/modules/home-environment.nix @@ -127,12 +127,40 @@ in example = { EDITOR = "emacs"; GS_OPTIONS = "-sPAPERSIZE=a4"; }; description = '' Environment variables to always set at login. + + The values may refer to other environment variables using + POSIX.2 style variable references. For example, a variable + parameter may be referenced as + $parameter or ''${parameter}. A + default value foo may be given as per + ''${parameter:-foo} and, similarly, an alternate + value bar can be given as per + ''${parameter:+bar}. + + Note, these variables may be set in any order so no session + variable may have a runtime dependency on another session + variable. In particular code like + + home.sessionVariables = { + FOO = "Hello"; + BAR = "$FOO World!"; + }; + + may not work as expected. If you need to reference another + session variable, then do so inside Nix instead. The above + example then becomes + + home.sessionVariables = { + FOO = "Hello"; + BAR = "''${config.home.sessionVariables.FOO} World!"; + }; + ''; }; home.sessionVariableSetter = mkOption { - default = "bash"; - type = types.enum [ "pam" "bash" "zsh" ]; + default = null; + type = types.nullOr (types.enum [ "pam" "bash" "zsh" ]); example = "pam"; description = '' Identifies the module that should set the session variables. @@ -143,6 +171,9 @@ in If "pam" is set then PAM must be used to set the system environment. Also mind that typical environment variables might not be set by the time PAM starts up. + + This option is DEPRECATED, the shell modules are now + automatically setting the session variables when enabled. ''; }; @@ -239,6 +270,23 @@ in // (maybeSet "LC_TIME" cfg.language.time); + home.packages = [ + # Provide a file holding all session variables. + ( + pkgs.writeTextFile { + name = "hm-session-vars.sh"; + destination = "/etc/profile.d/hm-session-vars.sh"; + text = '' + # Only source this once. + if [ -n "$__HM_SESS_VARS_SOURCED" ]; then return; fi + export __HM_SESS_VARS_SOURCED=1 + + ${config.lib.shell.exportAll cfg.sessionVariables} + ''; + } + ) + ]; + # A dummy entry acting as a boundary between the activation # script's "check" and the "write" phases. home.activation.writeBoundary = dag.entryAnywhere ""; diff --git a/modules/lib/default.nix b/modules/lib/default.nix index 5c273f15..8291be0b 100644 --- a/modules/lib/default.nix +++ b/modules/lib/default.nix @@ -15,4 +15,6 @@ entryAfter = d.dagEntryAfter; entryBefore = d.dagEntryBefore; }; + + shell = import ./shell.nix { inherit lib; }; } diff --git a/modules/lib/shell.nix b/modules/lib/shell.nix new file mode 100644 index 00000000..f1443c54 --- /dev/null +++ b/modules/lib/shell.nix @@ -0,0 +1,11 @@ +{ lib }: + +rec { + # Produces a Bourne shell like variable export statement. + export = n: v: "export ${n}=\"${toString v}\""; + + # Given an attribute set containing shell variable names and their + # assignment, this function produces a string containing an export + # statement for each set entry. + exportAll = vars: lib.concatStringsSep "\n" (lib.mapAttrsToList export vars); +} diff --git a/modules/misc/news.nix b/modules/misc/news.nix index 8ca9b7aa..5c11803e 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -478,6 +478,60 @@ in necessary. ''; } + + { + time = "2018-01-08T20:39:56+00:00"; + condition = config.home.sessionVariableSetter != null; + message = + let + opts = { + bash = '' + Instead the 'programs.bash' module will, when enabled, + automatically set session variables. You can safely + remove the 'home.sessionVariableSetter' option from your + configuration. + ''; + + zsh = '' + Instead the 'programs.zsh' module will, when enabled, + automatically set session variables. You can safely + remove the 'home.sessionVariableSetter' option from your + configuration. + ''; + + pam = '' + Unfortunately setting general session variables using + PAM will not be directly supported after this date. The + primary reason for this change is its limited support + for variable expansion. + + To continue setting session variables from the Home + Manager configuration you must either use the + 'programs.bash' or 'programs.zsh' modules or manually + source the session variable file + + $HOME/.nix-profile/etc/profile.d/hm-session-vars.sh + + within your shell configuration, see the README file for + more information. This file requires a Bourne-like shell + such as Bash or Z shell but hopefully other shells + will be supported in the future. + + If you specifically need to set a session variable using + PAM then the new option 'pam.sessionVariables' can be + used. It works much the same as 'home.sessionVariables' + but its attribute values must be valid within the PAM + environment file. + ''; + }; + in + '' + The 'home.sessionVariableSetter' option is now deprecated + and will be removed on February 8, 2018. + + ${opts.${config.home.sessionVariableSetter}} + ''; + } ]; }; } diff --git a/modules/misc/pam.nix b/modules/misc/pam.nix index 3bd0f292..dfeaf2f3 100644 --- a/modules/misc/pam.nix +++ b/modules/misc/pam.nix @@ -6,17 +6,35 @@ let homeCfg = config.home; + vars = + optionalAttrs (homeCfg.sessionVariableSetter == "pam") homeCfg.sessionVariables + // config.pam.sessionVariables; + in { meta.maintainers = [ maintainers.rycee ]; - options = {}; + options = { + pam.sessionVariables = mkOption { + default = {}; + type = types.attrs; + example = { EDITOR = "vim"; }; + description = '' + Environment variables that will be set for the PAM session. + The variable values must be as described in + + pam_env.conf + 5 + . + ''; + }; + }; - config = mkIf (homeCfg.sessionVariableSetter == "pam") { + config = mkIf (vars != {}) { home.file.".pam_environment".text = concatStringsSep "\n" ( - mapAttrsToList (n: v: "${n} OVERRIDE=${v}") homeCfg.sessionVariables + mapAttrsToList (n: v: "${n} OVERRIDE=${toString v}") vars ) + "\n"; }; } diff --git a/modules/programs/bash.nix b/modules/programs/bash.nix index 90ab5dd7..b5ac9417 100644 --- a/modules/programs/bash.nix +++ b/modules/programs/bash.nix @@ -131,31 +131,26 @@ in map (v: "shopt -s ${v}") cfg.shellOptions ); - export = n: v: "export ${n}=\"${toString v}\""; - setIfNonEmpty = n: v: optionalString (v != "") "${n}=${toString v}"; + sessionVarsStr = config.lib.shell.exportAll cfg.sessionVariables; - histControlStr = concatStringsSep ":" cfg.historyControl; - histIgnoreStr = concatStringsSep ":" cfg.historyIgnore; - - # If Bash is the session variable setter then this is the - # attribute set of global session variables, otherwise it is an - # empty set. - globalEnvVars = - optionalAttrs - (config.home.sessionVariableSetter == "bash") - config.home.sessionVariables; - - envVarsStr = concatStringsSep "\n" ( - mapAttrsToList export (cfg.sessionVariables // globalEnvVars) - ); + historyControlStr = + concatStringsSep "\n" (mapAttrsToList (n: v: "${n}=${v}") ( + { + HISTSIZE = toString cfg.historySize; + HISTFILESIZE = toString cfg.historyFileSize; + } + // optionalAttrs (cfg.historyControl != []) { + HISTCONTROL = concatStringsSep ":" cfg.historyControl; + } + // optionalAttrs (cfg.historyIgnore != []) { + HISTIGNORE = concatStringsSep ":" cfg.historyIgnore; + } + )); in mkIf cfg.enable { programs.bash.bashrcExtra = '' # Commands that should be applied only for interactive shells. if [[ -n $PS1 ]]; then - HISTSIZE=${toString cfg.historySize} - HISTFILESIZE=${toString cfg.historyFileSize} - ${setIfNonEmpty "HISTCONTROL" histControlStr} - ${setIfNonEmpty "HISTIGNORE" histIgnoreStr} + ${historyControlStr} ${shoptsStr} @@ -181,7 +176,11 @@ in home.file.".profile".text = '' # -*- mode: sh -*- - ${envVarsStr} + ${optionalString (config.home.sessionVariableSetter != "pam") '' + . "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh" + ''} + + ${sessionVarsStr} ${cfg.profileExtra} ''; diff --git a/modules/programs/zsh.nix b/modules/programs/zsh.nix index a088b332..4c97a921 100644 --- a/modules/programs/zsh.nix +++ b/modules/programs/zsh.nix @@ -11,17 +11,7 @@ let pluginsDir = if cfg.dotDir != null then relToDotDir "plugins" else ".zsh/plugins"; - export = n: v: "export ${n}=\"${toString v}\""; - - toEnvVarsStr = vars: concatStringsSep "\n" ( - mapAttrsToList export vars - ); - - envVars = cfg.sessionVariables // ( - if config.home.sessionVariableSetter == "zsh" then config.home.sessionVariables else {} - ); - - envVarsStr = toEnvVarsStr envVars; + envVarsStr = config.lib.shell.exportAll cfg.sessionVariables; aliasesStr = concatStringsSep "\n" ( mapAttrsToList (k: v: "alias ${k}='${v}'") cfg.shellAliases @@ -255,6 +245,9 @@ in home.file."${relToDotDir ".zshenv"}".text = '' typeset -U fpath + ${optionalString (config.home.sessionVariableSetter != "pam") '' + . "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh" + ''} ${envVarsStr} ''; diff --git a/modules/xsession.nix b/modules/xsession.nix index 9f06e76b..40e52202 100644 --- a/modules/xsession.nix +++ b/modules/xsession.nix @@ -82,6 +82,9 @@ in }; home.file.".xprofile".text = '' + ${optionalString (config.home.sessionVariableSetter != "pam") + ''. "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh"''} + if [[ -e "$HOME/.profile" ]]; then . "$HOME/.profile" fi