1 # This module defines a global environment configuration and
2 # a common configuration for all shells.
3 { config, lib, utils, pkgs, ... }:
6 cfg = config.environment;
11 lib.mapAttrs (n: lib.toList) cfg.variables;
14 lib.flip lib.mapAttrs cfg.profileRelativeEnvVars (envVar: listSuffixes:
15 lib.concatMap (profile: map (suffix: "${profile}${suffix}") listSuffixes) cfg.profiles
19 lib.zipAttrsWith (n: lib.concatLists) [ absoluteVariables suffixedVariables ];
22 lib.mapAttrsToList (n: v: ''export ${n}="${lib.concatStringsSep ":" v}"'') allVariables;
24 lib.concatStringsSep "\n" exportVariables;
31 environment.variables = lib.mkOption {
33 example = { EDITOR = "nvim"; VISUAL = "nvim"; };
35 A set of environment variables used in the global environment.
36 These variables will be set on shell initialisation (e.g. in /etc/profile).
37 The value of each variable can be either a string or a list of
38 strings. The latter is concatenated, interspersed with colon
41 type = with lib.types; attrsOf (oneOf [ (listOf (oneOf [ int str path ])) int str path ]);
43 toStr = v: if lib.isPath v then "${v}" else toString v;
44 in lib.mapAttrs (n: v: if lib.isList v then lib.concatMapStringsSep ":" toStr v else toStr v);
47 environment.profiles = lib.mkOption {
50 A list of profiles used to setup the global environment.
52 type = lib.types.listOf lib.types.str;
55 environment.profileRelativeEnvVars = lib.mkOption {
56 type = lib.types.attrsOf (lib.types.listOf lib.types.str);
57 example = { PATH = [ "/bin" ]; MANPATH = [ "/man" "/share/man" ]; };
59 Attribute set of environment variable. Each attribute maps to a list
60 of relative paths. Each relative path is appended to the each profile
61 of {option}`environment.profiles` to form the content of the
62 corresponding environment variable.
66 # !!! isn't there a better way?
67 environment.extraInit = lib.mkOption {
70 Shell script code called during global environment initialisation
71 after all variables and profileVariables have been set.
72 This code is assumed to be shell-independent, which means you should
73 stick to pure sh without sh word split.
75 type = lib.types.lines;
78 environment.shellInit = lib.mkOption {
81 Shell script code called during shell initialisation.
82 This code is assumed to be shell-independent, which means you should
83 stick to pure sh without sh word split.
85 type = lib.types.lines;
88 environment.loginShellInit = lib.mkOption {
91 Shell script code called during login shell initialisation.
92 This code is assumed to be shell-independent, which means you should
93 stick to pure sh without sh word split.
95 type = lib.types.lines;
98 environment.interactiveShellInit = lib.mkOption {
101 Shell script code called during interactive shell initialisation.
102 This code is assumed to be shell-independent, which means you should
103 stick to pure sh without sh word split.
105 type = lib.types.lines;
108 environment.shellAliases = lib.mkOption {
109 example = { l = null; ll = "ls -l"; };
111 An attribute set that maps aliases (the top level attribute names in
112 this option) to command strings or directly to build outputs. The
113 aliases are added to all users' shells.
114 Aliases mapped to `null` are ignored.
116 type = with lib.types; attrsOf (nullOr (either str path));
119 environment.homeBinInPath = lib.mkOption {
121 Include ~/bin/ in $PATH.
124 type = lib.types.bool;
127 environment.localBinInPath = lib.mkOption {
129 Add ~/.local/bin/ to $PATH
132 type = lib.types.bool;
135 environment.binsh = lib.mkOption {
136 default = "${config.system.build.binsh}/bin/sh";
137 defaultText = lib.literalExpression ''"''${config.system.build.binsh}/bin/sh"'';
138 example = lib.literalExpression ''"''${pkgs.dash}/bin/dash"'';
139 type = lib.types.path;
142 The shell executable that is linked system-wide to
143 `/bin/sh`. Please note that NixOS assumes all
144 over the place that shell to be Bash, so override the default
145 setting only if you know exactly what you're doing.
149 environment.shells = lib.mkOption {
151 example = lib.literalExpression "[ pkgs.bashInteractive pkgs.zsh ]";
153 A list of permissible login shells for user accounts.
154 No need to mention `/bin/sh`
155 here, it is placed into this list implicitly.
157 type = lib.types.listOf (lib.types.either lib.types.shellPackage lib.types.path);
164 system.build.binsh = pkgs.bashInteractive;
166 # Set session variables in the shell as well. This is usually
167 # unnecessary, but it allows changes to session variables to take
168 # effect without restarting the session (e.g. by opening a new
169 # terminal instead of logging out of X11).
170 environment.variables = config.environment.sessionVariables;
172 environment.profileRelativeEnvVars = config.environment.profileRelativeSessionVariables;
174 environment.shellAliases = lib.mapAttrs (name: lib.mkDefault) {
175 ls = "ls --color=tty";
180 environment.etc.shells.text =
182 ${lib.concatStringsSep "\n" (map utils.toShellPath cfg.shells)}
186 # For resetting environment with `. /etc/set-environment` when needed
187 # and discoverability (see motivation of #30418).
188 environment.etc.set-environment.source = config.system.build.setEnvironment;
190 system.build.setEnvironment = pkgs.writeText "set-environment"
192 # DO NOT EDIT -- this file has been generated automatically.
194 # Prevent this file from being sourced by child shells.
195 export __NIXOS_SET_ENVIRONMENT_DONE=1
201 ${lib.optionalString cfg.homeBinInPath ''
202 # ~/bin if it exists overrides other bin directories.
203 export PATH="$HOME/bin:$PATH"
206 ${lib.optionalString cfg.localBinInPath ''
207 export PATH="$HOME/.local/bin:$PATH"
211 system.activationScripts.binsh = lib.stringAfter [ "stdio" ]
213 # Create the required /bin/sh symlink; otherwise lots of things
214 # (notably the system() function) won't work.
217 ln -sfn "${cfg.binsh}" /bin/.sh.tmp
218 mv /bin/.sh.tmp /bin/sh # atomically replace /bin/sh