at 15.09-beta 6.4 kB view raw
1# This module defines a global environment configuration and 2# a common configuration for all shells. 3 4{ config, lib, pkgs, ... }: 5 6with lib; 7 8let 9 10 cfg = config.environment; 11 12 exportedEnvVars = 13 let 14 absoluteVariables = 15 mapAttrs (n: toList) cfg.variables; 16 17 suffixedVariables = 18 flip mapAttrs cfg.profileRelativeEnvVars (envVar: listSuffixes: 19 concatMap (profile: map (suffix: "${profile}${suffix}") listSuffixes) cfg.profiles 20 ); 21 22 allVariables = 23 zipAttrsWith (n: concatLists) [ absoluteVariables suffixedVariables ]; 24 25 exportVariables = 26 mapAttrsToList (n: v: ''export ${n}="${concatStringsSep ":" v}"'') allVariables; 27 in 28 concatStringsSep "\n" exportVariables; 29in 30 31{ 32 33 options = { 34 35 environment.variables = mkOption { 36 default = {}; 37 description = '' 38 A set of environment variables used in the global environment. 39 These variables will be set on shell initialisation. 40 The value of each variable can be either a string or a list of 41 strings. The latter is concatenated, interspersed with colon 42 characters. 43 ''; 44 type = types.attrsOf (mkOptionType { 45 name = "a string or a list of strings"; 46 merge = loc: defs: 47 let 48 defs' = filterOverrides defs; 49 res = (head defs').value; 50 in 51 if isList res then concatLists (getValues defs') 52 else if lessThan 1 (length defs') then 53 throw "The option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}." 54 else if !isString res then 55 throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}." 56 else res; 57 }); 58 apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v); 59 }; 60 61 environment.profiles = mkOption { 62 default = []; 63 description = '' 64 A list of profiles used to setup the global environment. 65 ''; 66 type = types.listOf types.str; 67 }; 68 69 environment.profileRelativeEnvVars = mkOption { 70 type = types.attrsOf (types.listOf types.str); 71 example = { PATH = [ "/bin" "/sbin" ]; MANPATH = [ "/man" "/share/man" ]; }; 72 description = '' 73 Attribute set of environment variable. Each attribute maps to a list 74 of relative paths. Each relative path is appended to the each profile 75 of <option>environment.profiles</option> to form the content of the 76 corresponding environment variable. 77 ''; 78 }; 79 80 # !!! isn't there a better way? 81 environment.extraInit = mkOption { 82 default = ""; 83 description = '' 84 Shell script code called during global environment initialisation 85 after all variables and profileVariables have been set. 86 This code is asumed to be shell-independent, which means you should 87 stick to pure sh without sh word split. 88 ''; 89 type = types.lines; 90 }; 91 92 environment.shellInit = mkOption { 93 default = ""; 94 description = '' 95 Shell script code called during shell initialisation. 96 This code is asumed to be shell-independent, which means you should 97 stick to pure sh without sh word split. 98 ''; 99 type = types.lines; 100 }; 101 102 environment.loginShellInit = mkOption { 103 default = ""; 104 description = '' 105 Shell script code called during login shell initialisation. 106 This code is asumed to be shell-independent, which means you should 107 stick to pure sh without sh word split. 108 ''; 109 type = types.lines; 110 }; 111 112 environment.interactiveShellInit = mkOption { 113 default = ""; 114 description = '' 115 Shell script code called during interactive shell initialisation. 116 This code is asumed to be shell-independent, which means you should 117 stick to pure sh without sh word split. 118 ''; 119 type = types.lines; 120 }; 121 122 environment.shellAliases = mkOption { 123 default = {}; 124 example = { ll = "ls -l"; }; 125 description = '' 126 An attribute set that maps aliases (the top level attribute names in 127 this option) to command strings or directly to build outputs. The 128 aliases are added to all users' shells. 129 ''; 130 type = types.attrs; # types.attrsOf types.stringOrPath; 131 }; 132 133 environment.binsh = mkOption { 134 default = "${config.system.build.binsh}/bin/sh"; 135 example = literalExample '' 136 "''${pkgs.dash}/bin/dash" 137 ''; 138 type = types.path; 139 description = '' 140 The shell executable that is linked system-wide to 141 <literal>/bin/sh</literal>. Please note that NixOS assumes all 142 over the place that shell to be Bash, so override the default 143 setting only if you know exactly what you're doing. 144 ''; 145 }; 146 147 environment.shells = mkOption { 148 default = []; 149 example = [ "/run/current-system/sw/bin/zsh" ]; 150 description = '' 151 A list of permissible login shells for user accounts. 152 No need to mention <literal>/bin/sh</literal> 153 here, it is placed into this list implicitly. 154 ''; 155 type = types.listOf types.path; 156 }; 157 158 }; 159 160 config = { 161 162 system.build.binsh = pkgs.bashInteractive; 163 164 # Set session variables in the shell as well. This is usually 165 # unnecessary, but it allows changes to session variables to take 166 # effect without restarting the session (e.g. by opening a new 167 # terminal instead of logging out of X11). 168 environment.variables = config.environment.sessionVariables; 169 170 environment.etc."shells".text = 171 '' 172 ${concatStringsSep "\n" cfg.shells} 173 /bin/sh 174 ''; 175 176 system.build.setEnvironment = pkgs.writeText "set-environment" 177 '' 178 ${exportedEnvVars} 179 180 ${cfg.extraInit} 181 182 # The setuid wrappers override other bin directories. 183 export PATH="${config.security.wrapperDir}:$PATH" 184 185 # ~/bin if it exists overrides other bin directories. 186 export PATH="$HOME/bin:$PATH" 187 ''; 188 189 system.activationScripts.binsh = stringAfter [ "stdio" ] 190 '' 191 # Create the required /bin/sh symlink; otherwise lots of things 192 # (notably the system() function) won't work. 193 mkdir -m 0755 -p /bin 194 ln -sfn "${cfg.binsh}" /bin/.sh.tmp 195 mv /bin/.sh.tmp /bin/sh # atomically replace /bin/sh 196 ''; 197 198 }; 199 200}