at 25.11-pre 7.9 kB view raw
1# This module defines a global environment configuration and 2# a common configuration for all shells. 3{ 4 config, 5 lib, 6 utils, 7 pkgs, 8 ... 9}: 10let 11 12 cfg = config.environment; 13 14 exportedEnvVars = 15 let 16 absoluteVariables = lib.mapAttrs (n: lib.toList) cfg.variables; 17 18 suffixedVariables = lib.flip lib.mapAttrs cfg.profileRelativeEnvVars ( 19 envVar: listSuffixes: 20 lib.concatMap (profile: map (suffix: "${profile}${suffix}") listSuffixes) cfg.profiles 21 ); 22 23 allVariables = lib.zipAttrsWith (n: lib.concatLists) [ 24 absoluteVariables 25 suffixedVariables 26 ]; 27 28 exportVariables = lib.mapAttrsToList ( 29 n: v: ''export ${n}="${lib.concatStringsSep ":" v}"'' 30 ) allVariables; 31 in 32 lib.concatStringsSep "\n" exportVariables; 33in 34 35{ 36 37 options = { 38 39 environment.variables = lib.mkOption { 40 default = { }; 41 example = { 42 EDITOR = "nvim"; 43 VISUAL = "nvim"; 44 }; 45 description = '' 46 A set of environment variables used in the global environment. 47 These variables will be set on shell initialisation (e.g. in /etc/profile). 48 49 The value of each variable can be either a string or a list of 50 strings. The latter is concatenated, interspersed with colon 51 characters. 52 53 Setting a variable to `null` does nothing. You can override a 54 variable set by another module to `null` to unset it. 55 ''; 56 type = 57 with lib.types; 58 attrsOf ( 59 nullOr (oneOf [ 60 (listOf (oneOf [ 61 int 62 str 63 path 64 ])) 65 int 66 str 67 path 68 ]) 69 ); 70 apply = 71 let 72 toStr = v: if lib.isPath v then "${v}" else toString v; 73 in 74 attrs: 75 lib.mapAttrs (n: v: if lib.isList v then lib.concatMapStringsSep ":" toStr v else toStr v) ( 76 lib.filterAttrs (n: v: v != null) attrs 77 ); 78 }; 79 80 environment.profiles = lib.mkOption { 81 default = [ ]; 82 description = '' 83 A list of profiles used to setup the global environment. 84 ''; 85 type = lib.types.listOf lib.types.str; 86 }; 87 88 environment.profileRelativeEnvVars = lib.mkOption { 89 type = lib.types.attrsOf (lib.types.listOf lib.types.str); 90 example = { 91 PATH = [ "/bin" ]; 92 MANPATH = [ 93 "/man" 94 "/share/man" 95 ]; 96 }; 97 description = '' 98 Attribute set of environment variable. Each attribute maps to a list 99 of relative paths. Each relative path is appended to the each profile 100 of {option}`environment.profiles` to form the content of the 101 corresponding environment variable. 102 ''; 103 }; 104 105 # !!! isn't there a better way? 106 environment.extraInit = lib.mkOption { 107 default = ""; 108 description = '' 109 Shell script code called during global environment initialisation 110 after all variables and profileVariables have been set. 111 This code is assumed to be shell-independent, which means you should 112 stick to pure sh without sh word split. 113 ''; 114 type = lib.types.lines; 115 }; 116 117 environment.shellInit = lib.mkOption { 118 default = ""; 119 description = '' 120 Shell script code called during shell initialisation. 121 This code is assumed to be shell-independent, which means you should 122 stick to pure sh without sh word split. 123 ''; 124 type = lib.types.lines; 125 }; 126 127 environment.loginShellInit = lib.mkOption { 128 default = ""; 129 description = '' 130 Shell script code called during login shell initialisation. 131 This code is assumed to be shell-independent, which means you should 132 stick to pure sh without sh word split. 133 ''; 134 type = lib.types.lines; 135 }; 136 137 environment.interactiveShellInit = lib.mkOption { 138 default = ""; 139 description = '' 140 Shell script code called during interactive shell initialisation. 141 This code is assumed to be shell-independent, which means you should 142 stick to pure sh without sh word split. 143 ''; 144 type = lib.types.lines; 145 }; 146 147 environment.shellAliases = lib.mkOption { 148 example = { 149 l = null; 150 ll = "ls -l"; 151 }; 152 description = '' 153 An attribute set that maps aliases (the top level attribute names in 154 this option) to command strings or directly to build outputs. The 155 aliases are added to all users' shells. 156 Aliases mapped to `null` are ignored. 157 ''; 158 type = with lib.types; attrsOf (nullOr (either str path)); 159 }; 160 161 environment.homeBinInPath = lib.mkOption { 162 description = '' 163 Include ~/bin/ in $PATH. 164 ''; 165 default = false; 166 type = lib.types.bool; 167 }; 168 169 environment.localBinInPath = lib.mkOption { 170 description = '' 171 Add ~/.local/bin/ to $PATH 172 ''; 173 default = false; 174 type = lib.types.bool; 175 }; 176 177 environment.binsh = lib.mkOption { 178 default = "${config.system.build.binsh}/bin/sh"; 179 defaultText = lib.literalExpression ''"''${config.system.build.binsh}/bin/sh"''; 180 example = lib.literalExpression ''"''${pkgs.dash}/bin/dash"''; 181 type = lib.types.path; 182 visible = false; 183 description = '' 184 The shell executable that is linked system-wide to 185 `/bin/sh`. Please note that NixOS assumes all 186 over the place that shell to be Bash, so override the default 187 setting only if you know exactly what you're doing. 188 ''; 189 }; 190 191 environment.shells = lib.mkOption { 192 default = [ ]; 193 example = lib.literalExpression "[ pkgs.bashInteractive pkgs.zsh ]"; 194 description = '' 195 A list of permissible login shells for user accounts. 196 No need to mention `/bin/sh` 197 here, it is placed into this list implicitly. 198 ''; 199 type = lib.types.listOf (lib.types.either lib.types.shellPackage lib.types.path); 200 }; 201 202 }; 203 204 config = { 205 206 system.build.binsh = pkgs.bashInteractive; 207 208 # Set session variables in the shell as well. This is usually 209 # unnecessary, but it allows changes to session variables to take 210 # effect without restarting the session (e.g. by opening a new 211 # terminal instead of logging out of X11). 212 environment.variables = config.environment.sessionVariables; 213 214 environment.profileRelativeEnvVars = config.environment.profileRelativeSessionVariables; 215 216 environment.shellAliases = lib.mapAttrs (name: lib.mkDefault) { 217 ls = "ls --color=tty"; 218 ll = "ls -l"; 219 l = "ls -alh"; 220 }; 221 222 environment.etc.shells.text = '' 223 ${lib.concatStringsSep "\n" (map utils.toShellPath cfg.shells)} 224 /bin/sh 225 ''; 226 227 # For resetting environment with `. /etc/set-environment` when needed 228 # and discoverability (see motivation of #30418). 229 environment.etc.set-environment.source = config.system.build.setEnvironment; 230 231 system.build.setEnvironment = pkgs.writeText "set-environment" '' 232 # DO NOT EDIT -- this file has been generated automatically. 233 234 # Prevent this file from being sourced by child shells. 235 export __NIXOS_SET_ENVIRONMENT_DONE=1 236 237 ${exportedEnvVars} 238 239 ${cfg.extraInit} 240 241 ${lib.optionalString cfg.homeBinInPath '' 242 # ~/bin if it exists overrides other bin directories. 243 export PATH="$HOME/bin:$PATH" 244 ''} 245 246 ${lib.optionalString cfg.localBinInPath '' 247 export PATH="$HOME/.local/bin:$PATH" 248 ''} 249 ''; 250 251 system.activationScripts.binsh = lib.stringAfter [ "stdio" ] '' 252 # Create the required /bin/sh symlink; otherwise lots of things 253 # (notably the system() function) won't work. 254 mkdir -p /bin 255 chmod 0755 /bin 256 ln -sfn "${cfg.binsh}" /bin/.sh.tmp 257 mv /bin/.sh.tmp /bin/sh # atomically replace /bin/sh 258 ''; 259 260 }; 261 262}