From b3f4040512b360397bb8989a85776335ff3c2847 Mon Sep 17 00:00:00 2001 From: Jan Malakhovski Date: Wed, 18 Sep 2013 03:18:34 +0000 Subject: [PATCH] Radically change the way NixOS handles environment variables and make it possible not to use Bash as the default interactive shell. This change does two things: * "NixOSizes" environment variables generation. This allows some more error-checking and opens possibilities for a modular environment configuration. From now on the most of environment variables are generated directly by the nix code. Generating sh code that generates environment variables is left in a few places where nontrivial access to a local environment state is needed. * By doing the first change this patch untangles bash from the environment configuration and makes it trivial to add a support for other non bash-compatible shells. Now to the sad part. This change is quite large (and I'm not sure it's possible to split it) and yet is not quite complete, it needs some changes to nixpkgs to be perfect. See !!! comments in modules/config/shells-environment.nix. Main principle behind this change is "change environment generation and nothing else". In particular, shell configuration principles stay exactly the same as before. --- modules/config/fonts/fontconfig.nix | 11 +- modules/config/i18n.nix | 5 +- modules/config/shells-environment.nix | 202 ++++++++++++++ modules/config/shells.nix | 24 -- modules/config/timezone.nix | 7 +- modules/module-list.nix | 3 +- modules/profiles/installation-device.nix | 6 +- modules/programs/bash/bash.nix | 255 +++++++++++------- modules/programs/bash/bashrc.sh | 19 -- modules/programs/bash/command-not-found.nix | 2 +- modules/programs/bash/profile.sh | 119 -------- modules/programs/environment.nix | 79 ++++++ modules/programs/shadow.nix | 4 +- modules/programs/shell.nix | 72 +++-- modules/rename.nix | 1 + modules/security/ca.nix | 10 +- modules/services/misc/nix-daemon.nix | 11 +- .../services/x11/desktop-managers/xfce.nix | 5 +- modules/services/x11/xserver.nix | 3 + modules/system/boot/modprobe.nix | 5 +- 20 files changed, 523 insertions(+), 320 deletions(-) create mode 100644 modules/config/shells-environment.nix delete mode 100644 modules/config/shells.nix delete mode 100644 modules/programs/bash/bashrc.sh delete mode 100644 modules/programs/bash/profile.sh create mode 100644 modules/programs/environment.nix diff --git a/modules/config/fonts/fontconfig.nix b/modules/config/fonts/fontconfig.nix index d0478083ed3..88643b41d83 100644 --- a/modules/config/fonts/fontconfig.nix +++ b/modules/config/fonts/fontconfig.nix @@ -46,13 +46,10 @@ with pkgs.lib; ''; - environment.shellInit = - '' - # FIXME: This variable is no longer needed, but we'll keep it - # around for a while for applications linked against old - # fontconfig builds. - export FONTCONFIG_FILE=/etc/fonts/fonts.conf - ''; + # FIXME: This variable is no longer needed, but we'll keep it + # around for a while for applications linked against old + # fontconfig builds. + environment.variables.FONTCONFIG_FILE.value = "/etc/fonts/fonts.conf"; environment.systemPackages = [ pkgs.fontconfig ]; diff --git a/modules/config/i18n.nix b/modules/config/i18n.nix index 62b01c2221e..15df0b3a12a 100644 --- a/modules/config/i18n.nix +++ b/modules/config/i18n.nix @@ -69,10 +69,7 @@ in environment.systemPackages = [ glibcLocales ]; - environment.shellInit = - '' - export LANG=${config.i18n.defaultLocale} - ''; + environment.variables.LANG.value = config.i18n.defaultLocale; # ‘/etc/locale.conf’ is used by systemd. environment.etc = singleton diff --git a/modules/config/shells-environment.nix b/modules/config/shells-environment.nix new file mode 100644 index 00000000000..116c5f11e1f --- /dev/null +++ b/modules/config/shells-environment.nix @@ -0,0 +1,202 @@ +# This module defines a global environment configuration and +# a common configuration for all shells. + +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.environment; + + environOpts = { name, config, ... }: { + + options = { + + value = mkOption { + example = "/foo/bin"; + description = + '' + Variable value. + Exactly one of this or must be set. + ''; + type = types.uniq types.string; + }; + + list = mkOption { + default = null; + example = [ "/foo/bin" "/bar/bin" ]; + description = + '' + Variable value. + Exactly one of this or must be set. + ''; + type = types.nullOr (types.listOf types.string); + }; + + }; + + config = { + value = mkIf (config.list != null) + (concatStringsSep ":" config.list); + }; + + }; + +in + +{ + + options = { + + environment.variables = mkOption { + default = {}; + description = '' + A set of environment variables used in the global environment. + ''; + type = types.attrsOf types.optionSet; + options = [ environOpts ]; + }; + + environment.profiles = mkOption { + default = []; + description = '' + A list of profiles used to setup the global environment. + ''; + type = types.listOf types.string; + }; + + environment.profileVariables = mkOption { + default = (p: {}); + description = '' + A function which given a profile path should give back + a set of environment variables for that profile. + ''; + # !!! this should be of the following type: + #type = types.functionTo (types.attrsOf (types.optionSet envVar)); + # and envVar should be changed to something more like environOpts. + # Having unique `value' _or_ multiple `list' is much more useful + # than just sticking everything together with ':' unconditionally. + # Anyway, to have this type mentioned above + # types.optionSet needs to be transformed into a type constructor + # (it has a !!! mark on that in nixpkgs) + # for now we hack all this to be + type = types.functionTo (types.attrsOf (types.listOf types.string)); + }; + + # !!! isn't there a better way? + environment.extraInit = mkOption { + default = ""; + description = '' + Shell script code called during global environment initialisation + after all variables and profileVariables have been set. + This code is asumed to be shell-independent, which means you should + stick to pure sh without sh word split. + ''; + type = types.lines; + }; + + environment.shellInit = mkOption { + default = ""; + description = '' + Shell script code called during shell initialisation. + This code is asumed to be shell-independent, which means you should + stick to pure sh without sh word split. + ''; + type = types.lines; + }; + + environment.loginShellInit = mkOption { + default = ""; + description = '' + Shell script code called during login shell initialisation. + This code is asumed to be shell-independent, which means you should + stick to pure sh without sh word split. + ''; + type = types.lines; + }; + + environment.interactiveShellInit = mkOption { + default = ""; + description = '' + Shell script code called during interactive shell initialisation. + This code is asumed to be shell-independent, which means you should + stick to pure sh without sh word split. + ''; + type = types.lines; + }; + + environment.shellAliases = mkOption { + default = {}; + example = { ll = "ls -l"; }; + description = '' + An attribute set that maps aliases (the top level attribute names in + this option) to command strings or directly to build outputs. The + aliases are added to all users' shells. + ''; + type = types.attrs; # types.attrsOf types.stringOrPath; + }; + + environment.binsh = mkOption { + default = "${config.system.build.binsh}/bin/sh"; + example = "\${pkgs.dash}/bin/dash"; + type = with pkgs.lib.types; path; + description = '' + The shell executable that is linked system-wide to + /bin/sh. Please note that NixOS assumes all + over the place that shell to be Bash, so override the default + setting only if you know exactly what you're doing. + ''; + }; + + environment.shells = mkOption { + default = []; + example = [ "/run/current-system/sw/bin/zsh" ]; + description = '' + A list of permissible login shells for user accounts. + No need to mention /bin/sh + here, it is placed into this list implicitly. + ''; + type = types.listOf types.path; + }; + + }; + + config = { + + system.build.binsh = pkgs.bashInteractive; + + environment.etc."shells".text = + '' + ${concatStringsSep "\n" cfg.shells} + /bin/sh + ''; + + environment.etc."environment".text = + '' + ${concatStringsSep "\n" ( + (mapAttrsToList (n: v: ''export ${n}="${concatStringsSep ":" v}"'') + # This line is a kind of a hack because of !!! note above + (fold (mergeAttrsWithFunc concat) {} ([ (mapAttrs (n: v: [ v.value ]) cfg.variables) ] ++ map cfg.profileVariables cfg.profiles))))} + + ${cfg.extraInit} + + # The setuid wrappers override other bin directories. + export PATH="${config.security.wrapperDir}:$PATH" + + # ~/bin if it exists overrides other bin directories. + export PATH="$HOME/bin:$PATH" + ''; + + system.activationScripts.binsh = stringAfter [ "stdio" ] + '' + # Create the required /bin/sh symlink; otherwise lots of things + # (notably the system() function) won't work. + mkdir -m 0755 -p /bin + ln -sfn "${cfg.binsh}" /bin/.sh.tmp + mv /bin/.sh.tmp /bin/sh # atomically replace /bin/sh + ''; + + }; + +} diff --git a/modules/config/shells.nix b/modules/config/shells.nix deleted file mode 100644 index b0a946a8e6e..00000000000 --- a/modules/config/shells.nix +++ /dev/null @@ -1,24 +0,0 @@ -# This module creates /etc/shells, the file that defines the list of -# permissible login shells for user accounts. - -{ config, pkgs, ... }: - -with pkgs.lib; - -{ - - config = { - - environment.etc = singleton - { target = "shells"; - source = pkgs.writeText "shells" - '' - /run/current-system/sw/bin/bash - /var/run/current-system/sw/bin/bash - /bin/sh - ''; - }; - - }; - -} diff --git a/modules/config/timezone.nix b/modules/config/timezone.nix index 81536725501..68b785601fa 100644 --- a/modules/config/timezone.nix +++ b/modules/config/timezone.nix @@ -24,11 +24,8 @@ with pkgs.lib; config = { - environment.shellInit = - '' - export TZDIR=/etc/zoneinfo - export TZ=${config.time.timeZone} - ''; + environment.variables.TZDIR.value = "/etc/zoneinfo"; + environment.variables.TZ.value = config.time.timeZone; environment.etc.localtime.source = "${pkgs.tzdata}/share/zoneinfo/${config.time.timeZone}"; diff --git a/modules/module-list.nix b/modules/module-list.nix index 08acd213355..3a7ede02396 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -13,7 +13,7 @@ ./config/nsswitch.nix ./config/power-management.nix ./config/pulseaudio.nix - ./config/shells.nix + ./config/shells-environment.nix ./config/swap.nix ./config/sysctl.nix ./config/system-path.nix @@ -45,6 +45,7 @@ ./programs/bash/bash.nix ./programs/bash/command-not-found.nix ./programs/blcr.nix + ./programs/environment.nix ./programs/info.nix ./programs/shadow.nix ./programs/shell.nix diff --git a/modules/profiles/installation-device.nix b/modules/profiles/installation-device.nix index 5a92789e5d9..cfb2eb3f9cb 100644 --- a/modules/profiles/installation-device.nix +++ b/modules/profiles/installation-device.nix @@ -50,9 +50,7 @@ with pkgs.lib; # Tell the Nix evaluator to garbage collect more aggressively. # This is desirable in memory-constrained environments that don't # (yet) have swap set up. - environment.shellInit = - '' - export GC_INITIAL_HEAP_SIZE=100000 - ''; + environment.variables.GC_INITIAL_HEAP_SIZE.value = "100000"; + }; } diff --git a/modules/programs/bash/bash.nix b/modules/programs/bash/bash.nix index 0d751d1d0d3..2324164316d 100644 --- a/modules/programs/bash/bash.nix +++ b/modules/programs/bash/bash.nix @@ -7,9 +7,11 @@ with pkgs.lib; let - cfg = config.environment; + cfge = config.environment; - initBashCompletion = optionalString cfg.enableBashCompletion '' + cfg = config.programs.bash; + + bashCompletion = optionalString cfg.enableCompletion '' # Check whether we're running a version of Bash that has support for # programmable completion. If we do, enable all modules installed in # the system (and user profile). @@ -27,7 +29,7 @@ let fi ''; - shellAliases = concatStringsSep "\n" ( + bashAliases = concatStringsSep "\n" ( mapAttrsFlatten (k: v: "alias ${k}='${v}'") cfg.shellAliases ); @@ -36,118 +38,173 @@ in { options = { - environment.promptInit = mkOption { - default = '' - # Provide a nice prompt. - PROMPT_COLOR="1;31m" - let $UID && PROMPT_COLOR="1;32m" - PS1="\n\[\033[$PROMPT_COLOR\][\u@\h:\w]\\$\[\033[0m\] " - if test "$TERM" = "xterm"; then - PS1="\[\033]2;\h:\u:\w\007\]$PS1" - fi - ''; - description = '' - Shell script code used to initialise the shell prompt. - ''; - type = types.lines; - }; + programs.bash = { - environment.shellInit = mkOption { - default = ""; - example = ''export PATH=/godi/bin/:$PATH''; - description = '' - Shell script code called during login shell initialisation. - ''; - type = types.lines; - }; + enable = mkOption { + default = true; + description = '' + Whenever to configure Bash as an interactive shell. + Note that this tries to make Bash the default + , + which in turn means that you might need to explicitly + set this variable if you have another shell configured + with NixOS. + ''; + type = types.bool; + }; - environment.interactiveShellInit = mkOption { - default = ""; - example = ''export PATH=/godi/bin/:$PATH''; - description = '' - Shell script code called during interactive shell initialisation. - ''; - type = types.lines; - }; + shellAliases = mkOption { + default = config.environment.shellAliases // { which = "type -P"; }; + description = '' + Set of aliases for bash shell. See + for an option format description. + ''; + type = types.attrs; # types.attrsOf types.stringOrPath; + }; - environment.enableBashCompletion = mkOption { - default = false; - description = "Enable Bash completion for all interactive shells."; - type = types.bool; - }; + shellInit = mkOption { + default = ""; + description = '' + Shell script code called during bash shell initialisation. + ''; + type = types.lines; + }; + + loginShellInit = mkOption { + default = ""; + description = '' + Shell script code called during login bash shell initialisation. + ''; + type = types.lines; + }; + + interactiveShellInit = mkOption { + default = ""; + description = '' + Shell script code called during interactive bash shell initialisation. + ''; + type = types.lines; + }; + + promptInit = mkOption { + default = '' + # Provide a nice prompt. + PROMPT_COLOR="1;31m" + let $UID && PROMPT_COLOR="1;32m" + PS1="\n\[\033[$PROMPT_COLOR\][\u@\h:\w]\\$\[\033[0m\] " + if test "$TERM" = "xterm"; then + PS1="\[\033]2;\h:\u:\w\007\]$PS1" + fi + ''; + description = '' + Shell script code used to initialise the bash prompt. + ''; + type = types.lines; + }; + + enableCompletion = mkOption { + default = false; + description = '' + Enable Bash completion for all interactive bash shells. + ''; + type = types.bool; + }; - environment.binsh = mkOption { - default = "${config.system.build.binsh}/bin/sh"; - example = "\${pkgs.dash}/bin/dash"; - type = types.path; - description = '' - Select the shell executable that is linked system-wide to - /bin/sh. Please note that NixOS assumes all - over the place that shell to be Bash, so override the default - setting only if you know exactly what you're doing. - ''; }; }; + config = mkIf cfg.enable { - config = { + programs.bash = { - # Script executed when the shell starts as a login shell. - environment.etc."profile".source = - pkgs.substituteAll { - src = ./profile.sh; - wrapperDir = config.security.wrapperDir; - inherit (cfg) shellInit; - }; + shellInit = '' + . /etc/environment - # /etc/bashrc: executed every time an interactive bash - # starts. Sources /etc/profile to ensure that the system - # environment is configured properly. - environment.etc."bashrc".source = - pkgs.substituteAll { - src = ./bashrc.sh; - inherit (cfg) interactiveShellInit; - }; + ${cfge.shellInit} + ''; + + loginShellInit = cfge.loginShellInit; + + interactiveShellInit = '' + ${cfge.interactiveShellInit} + + # Check the window size after every command. + shopt -s checkwinsize + + # Disable hashing (i.e. caching) of command lookups. + set +h + + ${cfg.promptInit} + ${bashCompletion} + ${bashAliases} + ''; + + }; + + environment.etc."profile".text = + '' + # /etc/profile: DO NOT EDIT -- this file has been generated automatically. + # This file is read for login shells. + + # Only execute this file once per shell. + if [ -n "$__ETC_PROFILE_SOURCED" ]; then return; fi + __ETC_PROFILE_SOURCED=1 + + if [ -z "$__BASH_SHELL_INIT_DONE" ]; then + __BASH_SHELL_INIT_DONE=1 + ${cfg.shellInit} + fi + + ${cfg.loginShellInit} + + # Read system-wide modifications. + if test -f /etc/profile.local; then + . /etc/profile.local + fi + + if [ -n "''${BASH_VERSION:-}" ]; then + . /etc/bashrc + fi + ''; + + environment.etc."bashrc".text = + '' + # /etc/bashrc: DO NOT EDIT -- this file has been generated automatically. + + # Only execute this file once per shell. + if [ -n "$__ETC_BASHRC_SOURCED" -o -n "$NOSYSBASHRC" ]; then return; fi + __ETC_BASHRC_SOURCED=1 + + if [ -z "$__BASH_SHELL_INIT_DONE" ]; then + __BASH_SHELL_INIT_DONE=1 + ${cfg.shellInit} + fi + + # We are not always an interactive shell. + if [ -n "$PS1" ]; then + ${cfg.interactiveShellInit} + fi + + # Read system-wide modifications. + if test -f /etc/bashrc.local; then + . /etc/bashrc.local + fi + ''; # Configuration for readline in bash. environment.etc."inputrc".source = ./inputrc; - environment.shellAliases = - { ls = "ls --color=tty"; - ll = "ls -l"; - l = "ls -alh"; - which = "type -P"; - }; + users.defaultUserShell = mkDefault "/run/current-system/sw/bin/bash"; - environment.interactiveShellInit = - '' - # Check the window size after every command. - shopt -s checkwinsize - - ${cfg.promptInit} - ${initBashCompletion} - ${shellAliases} - - # Disable hashing (i.e. caching) of command lookups. - set +h - ''; - - system.build.binsh = pkgs.bashInteractive; - - system.activationScripts.binsh = stringAfter [ "stdio" ] - '' - # Create the required /bin/sh symlink; otherwise lots of things - # (notably the system() function) won't work. - mkdir -m 0755 -p /bin - ln -sfn "${cfg.binsh}" /bin/.sh.tmp - mv /bin/.sh.tmp /bin/sh # atomically replace /bin/sh - ''; - - environment.pathsToLink = optionals cfg.enableBashCompletion [ - "/etc/bash_completion.d" - "/share/bash-completion" - ]; + environment.shells = + [ "/run/current-system/sw/bin/bash" + "/var/run/current-system/sw/bin/bash" + "/run/current-system/sw/bin/sh" + "/var/run/current-system/sw/bin/sh" + "${pkgs.bashInteractive}/bin/bash" + "${pkgs.bashInteractive}/bin/sh" + ]; }; diff --git a/modules/programs/bash/bashrc.sh b/modules/programs/bash/bashrc.sh deleted file mode 100644 index 98b0907a06b..00000000000 --- a/modules/programs/bash/bashrc.sh +++ /dev/null @@ -1,19 +0,0 @@ -# /etc/bashrc: DO NOT EDIT -- this file has been generated automatically. - -# This file is read for interactive non-login shells. - -# Only execute this file once per shell. -if [ -n "$__ETC_BASHRC_SOURCED" -o -n "$NOSYSBASHRC" ]; then return; fi -__ETC_BASHRC_SOURCED=1 - -# If the profile was not loaded in a parent process, source it. But -# otherwise don't do it because we don't want to clobber overridden -# values of $PATH, etc. -if [ -z "$__ETC_PROFILE_DONE" ]; then - . /etc/profile -fi - -# We are not always an interactive shell. -if [ -z "$PS1" ]; then return; fi - -@interactiveShellInit@ diff --git a/modules/programs/bash/command-not-found.nix b/modules/programs/bash/command-not-found.nix index 6549ba86810..502320446a3 100644 --- a/modules/programs/bash/command-not-found.nix +++ b/modules/programs/bash/command-not-found.nix @@ -23,7 +23,7 @@ in { - environment.interactiveShellInit = + programs.bash.interactiveShellInit = '' # This function is called whenever a command is not found. command_not_found_handle() { diff --git a/modules/programs/bash/profile.sh b/modules/programs/bash/profile.sh deleted file mode 100644 index 92fb0658189..00000000000 --- a/modules/programs/bash/profile.sh +++ /dev/null @@ -1,119 +0,0 @@ -# /etc/profile: DO NOT EDIT -- this file has been generated automatically. - -# This file is read for (interactive) login shells. Any -# initialisation specific to interactive shells should be put in -# /etc/bashrc, which is sourced from here. - -# Only execute this file once per shell. -if [ -n "$__ETC_PROFILE_SOURCED" ]; then return; fi -__ETC_PROFILE_SOURCED=1 - -# Prevent this file from being sourced by interactive non-login child shells. -export __ETC_PROFILE_DONE=1 - -# Initialise a bunch of environment variables. -export LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive -export LD_LIBRARY_PATH=/run/opengl-driver/lib:/run/opengl-driver-32/lib # !!! only set if needed -export NIXPKGS_CONFIG=/etc/nix/nixpkgs-config.nix -export NIX_PATH=/nix/var/nix/profiles/per-user/root/channels/nixos:nixpkgs=/etc/nixos/nixpkgs:nixos=/etc/nixos/nixos:nixos-config=/etc/nixos/configuration.nix:services=/etc/nixos/services -export PAGER="less -R" -export EDITOR=nano -export LOCATE_PATH=/var/cache/locatedb - -# Include the various profiles in the appropriate environment variables. -export NIX_USER_PROFILE_DIR=/nix/var/nix/profiles/per-user/$USER -export NIX_PROFILES="/run/current-system/sw /nix/var/nix/profiles/default $HOME/.nix-profile" - -unset PATH INFOPATH PKG_CONFIG_PATH PERL5LIB ALSA_PLUGIN_DIRS GST_PLUGIN_PATH KDEDIRS -unset QT_PLUGIN_PATH QTWEBKIT_PLUGIN_PATH STRIGI_PLUGIN_PATH XDG_CONFIG_DIRS XDG_DATA_DIRS -unset MOZ_PLUGIN_PATH TERMINFO_DIRS - -for i in $NIX_PROFILES; do # !!! reverse - # We have to care not leaving an empty PATH element, because that means '.' to Linux - export PATH=$i/bin:$i/sbin:$i/lib/kde4/libexec${PATH:+:}$PATH - export INFOPATH=$i/info:$i/share/info${INFOPATH:+:}$INFOPATH - export PKG_CONFIG_PATH="$i/lib/pkgconfig${PKG_CONFIG_PATH:+:}$PKG_CONFIG_PATH" - - # terminfo and reset TERM with new TERMINFO available - export TERMINFO_DIRS=$i/share/terminfo${TERMINFO_DIRS:+:}$TERMINFO_DIRS - export TERM=$TERM - - export PERL5LIB="$i/lib/perl5/site_perl${PERL5LIB:+:}$PERL5LIB" - - # ALSA plugins - export ALSA_PLUGIN_DIRS="$i/lib/alsa-lib${ALSA_PLUGIN_DIRS:+:}$ALSA_PLUGIN_DIRS" - - # GStreamer. - export GST_PLUGIN_PATH="$i/lib/gstreamer-0.10${GST_PLUGIN_PATH:+:}$GST_PLUGIN_PATH" - - # KDE/Gnome stuff. - export KDEDIRS=$i${KDEDIRS:+:}$KDEDIRS - export STRIGI_PLUGIN_PATH=$i/lib/strigi/${STRIGI_PLUGIN_PATH:+:}$STRIGI_PLUGIN_PATH - export QT_PLUGIN_PATH=$i/lib/qt4/plugins:$i/lib/kde4/plugins${QT_PLUGIN_PATH:+:}:$QT_PLUGIN_PATH - export QTWEBKIT_PLUGIN_PATH=$i/lib/mozilla/plugins/${QTWEBKIT_PLUGIN_PATH:+:}$QTWEBKIT_PLUGIN_PATH - export XDG_CONFIG_DIRS=$i/etc/xdg${XDG_CONFIG_DIRS:+:}$XDG_CONFIG_DIRS - export XDG_DATA_DIRS=$i/share${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS - - # Mozilla plugins. - export MOZ_PLUGIN_PATH=$i/lib/mozilla/plugins${MOZ_PLUGIN_PATH:+:}$MOZ_PLUGIN_PATH - - # Search directory for Aspell dictionaries. - if [ -d "$i/lib/aspell" ]; then - export ASPELL_CONF="dict-dir $i/lib/aspell" - fi -done - -# The setuid wrappers override other bin directories. -export PATH=@wrapperDir@:$PATH - -# ~/bin if it exists overrides other bin directories. -export PATH=$HOME/bin:$PATH - -# Set up the per-user profile. -mkdir -m 0755 -p $NIX_USER_PROFILE_DIR -if test "$(stat --printf '%u' $NIX_USER_PROFILE_DIR)" != "$(id -u)"; then - echo "WARNING: bad ownership on $NIX_USER_PROFILE_DIR" >&2 -fi - -if ! test -L $HOME/.nix-profile; then - echo "creating $HOME/.nix-profile" >&2 - if test "$USER" != root; then - ln -s $NIX_USER_PROFILE_DIR/profile $HOME/.nix-profile - else - # Root installs in the system-wide profile by default. - ln -s /nix/var/nix/profiles/default $HOME/.nix-profile - fi -fi - -# Subscribe the root user to the NixOS channel by default. -if [ "$USER" = root -a ! -e $HOME/.nix-channels ]; then - echo "http://nixos.org/channels/nixos-unstable nixos" > $HOME/.nix-channels -fi - -# Create the per-user garbage collector roots directory. -NIX_USER_GCROOTS_DIR=/nix/var/nix/gcroots/per-user/$USER -mkdir -m 0755 -p $NIX_USER_GCROOTS_DIR -if test "$(stat --printf '%u' $NIX_USER_GCROOTS_DIR)" != "$(id -u)"; then - echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR" >&2 -fi - -# Set up a default Nix expression from which to install stuff. -if [ ! -e $HOME/.nix-defexpr -o -L $HOME/.nix-defexpr ]; then - echo "creating $HOME/.nix-defexpr" >&2 - rm -f $HOME/.nix-defexpr - mkdir $HOME/.nix-defexpr - if [ "$USER" != root ]; then - ln -s /nix/var/nix/profiles/per-user/root/channels $HOME/.nix-defexpr/channels_root - fi -fi - -@shellInit@ - -# Read system-wide modifications. -if test -f /etc/profile.local; then - . /etc/profile.local -fi - -if [ -n "${BASH_VERSION:-}" ]; then - . /etc/bashrc -fi diff --git a/modules/programs/environment.nix b/modules/programs/environment.nix new file mode 100644 index 00000000000..8f2df7e4a53 --- /dev/null +++ b/modules/programs/environment.nix @@ -0,0 +1,79 @@ +# This module defines a standard configuration for NixOS global environment. + +# Most of the stuff here should probably be moved elsewhere sometime. + +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.environment; + +in + +{ + + config = { + + environment.variables = + { LOCALE_ARCHIVE.value = "/run/current-system/sw/lib/locale/locale-archive"; + LOCATE_PATH.value = "/var/cache/locatedb"; + NIXPKGS_CONFIG.value = "/etc/nix/nixpkgs-config.nix"; + NIX_PATH.list = + [ "/nix/var/nix/profiles/per-user/root/channels/nixos" + "nixpkgs=/etc/nixos/nixpkgs" + "nixos=/etc/nixos/nixos" + "nixos-config=/etc/nixos/configuration.nix" + "services=/etc/nixos/services" + ]; + PAGER.value = "less -R"; + EDITOR.value = "nano"; + }; + + environment.profiles = + [ "$HOME/.nix-profile" + "/nix/var/nix/profiles/default" + "/run/current-system/sw" + ]; + + # !!! fix environment.profileVariables definition and then move + # most of these elsewhere + environment.profileVariables = (i: + { PATH = [ "${i}/bin" "${i}/sbin" "${i}/lib/kde4/libexec" ]; + MANPATH = [ "${i}/man" "${i}/share/man" ]; + INFOPATH = [ "${i}/info" "${i}/share/info" ]; + PKG_CONFIG_PATH = [ "${i}/lib/pkgconfig" ]; + TERMINFO_DIRS = [ "${i}/share/terminfo" ]; + PERL5LIB = [ "${i}/lib/perl5/site_perl" ]; + ALSA_PLUGIN_DIRS = [ "${i}/lib/alsa-lib" ]; + GST_PLUGIN_PATH = [ "${i}/lib/gstreamer-0.10" ]; + KDEDIRS = [ "${i}" ]; + STRIGI_PLUGIN_PATH = [ "${i}/lib/strigi/" ]; + QT_PLUGIN_PATH = [ "${i}/lib/qt4/plugins" "${i}/lib/kde4/plugins" ]; + QTWEBKIT_PLUGIN_PATH = [ "${i}/lib/mozilla/plugins/" ]; + GTK_PATH = [ "${i}/lib/gtk-2.0" ]; + XDG_CONFIG_DIRS = [ "${i}/etc/xdg" ]; + XDG_DATA_DIRS = [ "${i}/share" ]; + MOZ_PLUGIN_PATH = [ "${i}/lib/mozilla/plugins" ]; + }); + + environment.extraInit = + '' + # reset TERM with new TERMINFO available (if any) + export TERM=$TERM + + unset ASPELL_CONF + for i in ${concatStringsSep " " (reverseList cfg.profiles)} ; do + if [ -d "$i/lib/aspell" ]; then + export ASPELL_CONF="dict-dir $i/lib/aspell" + fi + done + + export NIX_USER_PROFILE_DIR="/nix/var/nix/profiles/per-user/$USER" + export NIX_PROFILES="${concatStringsSep " " (reverseList cfg.profiles)}" + ''; + + }; + +} diff --git a/modules/programs/shadow.nix b/modules/programs/shadow.nix index 39359ac4293..9f62e62beb1 100644 --- a/modules/programs/shadow.nix +++ b/modules/programs/shadow.nix @@ -2,6 +2,8 @@ { config, pkgs, ... }: +with pkgs.lib; + let loginDefs = @@ -39,7 +41,6 @@ in options = { users.defaultUserShell = pkgs.lib.mkOption { - default = "/run/current-system/sw/bin/bash"; description = '' This option defines the default shell assigned to user accounts. This must not be a store path, since the path is @@ -47,6 +48,7 @@ in Rather, it should be the path of a symlink that points to the actual shell in the Nix store. ''; + type = types.uniq types.path; }; }; diff --git a/modules/programs/shell.nix b/modules/programs/shell.nix index 8348c4c25a1..d5f43a86a94 100644 --- a/modules/programs/shell.nix +++ b/modules/programs/shell.nix @@ -1,25 +1,67 @@ -# This module defines global configuration for the shells. +# This module defines a standard configuration for NixOS shells. { config, pkgs, ... }: with pkgs.lib; +let + + cfg = config.environment; + +in + { - options = { - environment.shellAliases = mkOption { - type = types.attrs; # types.attrsOf types.stringOrPath; - default = {}; - example = { - ll = "ls -lh"; - }; - description = '' - An attribute set that maps aliases (the top level attribute names in - this option) to command strings or directly to build outputs. The - aliases are added to all users' shells. - ''; - }; - }; config = { + + environment.shellAliases = + { ls = "ls --color=tty"; + ll = "ls -l"; + l = "ls -alh"; + }; + + environment.shellInit = + '' + # Set up the per-user profile. + mkdir -m 0755 -p $NIX_USER_PROFILE_DIR + if test "$(stat --printf '%u' $NIX_USER_PROFILE_DIR)" != "$(id -u)"; then + echo "WARNING: bad ownership on $NIX_USER_PROFILE_DIR" >&2 + fi + + if ! test -L $HOME/.nix-profile; then + echo "creating $HOME/.nix-profile" >&2 + if test "$USER" != root; then + ln -s $NIX_USER_PROFILE_DIR/profile $HOME/.nix-profile + else + # Root installs in the system-wide profile by default. + ln -s /nix/var/nix/profiles/default $HOME/.nix-profile + fi + fi + + # Subscribe the root user to the NixOS channel by default. + if [ "$USER" = root -a ! -e $HOME/.nix-channels ]; then + echo "creating $HOME/.nix-channels with nixos-unstable subscription" >&2 + echo "http://nixos.org/channels/nixos-unstable nixos" > $HOME/.nix-channels + fi + + # Create the per-user garbage collector roots directory. + NIX_USER_GCROOTS_DIR=/nix/var/nix/gcroots/per-user/$USER + mkdir -m 0755 -p $NIX_USER_GCROOTS_DIR + if test "$(stat --printf '%u' $NIX_USER_GCROOTS_DIR)" != "$(id -u)"; then + echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR" >&2 + fi + + # Set up a default Nix expression from which to install stuff. + if [ ! -e $HOME/.nix-defexpr -o -L $HOME/.nix-defexpr ]; then + echo "creating $HOME/.nix-defexpr" >&2 + rm -f $HOME/.nix-defexpr + mkdir $HOME/.nix-defexpr + if [ "$USER" != root ]; then + ln -s /nix/var/nix/profiles/per-user/root/channels $HOME/.nix-defexpr/channels_root + fi + fi + ''; + }; + } diff --git a/modules/rename.nix b/modules/rename.nix index bc0ebf1f091..ef86befe9e7 100644 --- a/modules/rename.nix +++ b/modules/rename.nix @@ -66,6 +66,7 @@ in zipModules ([] # usage example: # ++ rename alias "services.xserver.slim.theme" "services.xserver.displayManager.slim.theme" ++ rename obsolete "environment.extraPackages" "environment.systemPackages" +++ rename obsolete "environment.enableBashCompletion" "programs.bash.enableCompletion" ++ rename obsolete "security.extraSetuidPrograms" "security.setuidPrograms" ++ rename obsolete "networking.enableWLAN" "networking.wireless.enable" diff --git a/modules/security/ca.nix b/modules/security/ca.nix index e42f5ffe3b8..f0897630eac 100644 --- a/modules/security/ca.nix +++ b/modules/security/ca.nix @@ -17,13 +17,9 @@ with pkgs.lib; } ]; - environment.shellInit = - '' - export OPENSSL_X509_CERT_FILE=/etc/ssl/certs/ca-bundle.crt - - export CURL_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt - export GIT_SSL_CAINFO=/etc/ssl/certs/ca-bundle.crt - ''; + environment.variables.OPENSSL_X509_CERT_FILE.value = "/etc/ssl/certs/ca-bundle.crt"; + environment.variables.CURL_CA_BUNDLE.value = "/etc/ssl/certs/ca-bundle.crt"; + environment.variables.GIT_SSL_CAINFO.value = "/etc/ssl/certs/ca-bundle.crt"; }; diff --git a/modules/services/misc/nix-daemon.nix b/modules/services/misc/nix-daemon.nix index 6ae96028979..9dd58fbab20 100644 --- a/modules/services/misc/nix-daemon.nix +++ b/modules/services/misc/nix-daemon.nix @@ -198,8 +198,7 @@ in example = "http://127.0.0.1:3128"; }; - # Environment variables for running Nix. !!! Misnomer - it's - # actually a shell script. + # Environment variables for running Nix. envVars = mkOption { internal = true; default = {}; @@ -328,11 +327,11 @@ in ftp_proxy = cfg.proxy; }; - environment.shellInit = - '' - # Set up the environment variables for running Nix. - ${concatMapStrings (n: "export ${n}=\"${getAttr n cfg.envVars}\"\n") (attrNames cfg.envVars)} + # Set up the environment variables for running Nix. + environment.variables = mapAttrs (n: v: { value = v; }) cfg.envVars; + environment.extraInit = + '' # Set up secure multi-user builds: non-root users build through the # Nix daemon. if test "$USER" != root; then diff --git a/modules/services/x11/desktop-managers/xfce.nix b/modules/services/x11/desktop-managers/xfce.nix index e22e6a12130..6197a7e10aa 100644 --- a/modules/services/x11/desktop-managers/xfce.nix +++ b/modules/services/x11/desktop-managers/xfce.nix @@ -79,10 +79,7 @@ in environment.pathsToLink = [ "/share/xfce4" "/share/themes" "/share/mime" "/share/desktop-directories" "/share/gtksourceview-2.0" ]; - environment.shellInit = - '' - export GIO_EXTRA_MODULES=${pkgs.xfce.gvfs}/lib/gio/modules - ''; + environment.variables.GIO_EXTRA_MODULES.value = "${pkgs.xfce.gvfs}/lib/gio/modules"; # Enable helpful DBus services. services.udisks2.enable = true; diff --git a/modules/services/x11/xserver.nix b/modules/services/x11/xserver.nix index 40da6a74389..2c76361ea4b 100644 --- a/modules/services/x11/xserver.nix +++ b/modules/services/x11/xserver.nix @@ -409,6 +409,9 @@ in boot.blacklistedKernelModules = optionals (elem "nvidia" driverNames) [ "nouveau" "nvidiafb" ]; + environment.variables.LD_LIBRARY_PATH.list = + [ "/run/opengl-driver/lib" "/run/opengl-driver-32/lib" ]; + environment.etc = (optionals cfg.exportConfiguration [ { source = "${configFile}"; diff --git a/modules/system/boot/modprobe.nix b/modules/system/boot/modprobe.nix index 62ac3009d10..c1c65bed64f 100644 --- a/modules/system/boot/modprobe.nix +++ b/modules/system/boot/modprobe.nix @@ -105,10 +105,7 @@ with pkgs.lib; echo ${config.system.sbin.modprobe}/sbin/modprobe > /proc/sys/kernel/modprobe ''; - environment.shellInit = - '' - export MODULE_DIR=/run/current-system/kernel-modules/lib/modules - ''; + environment.variables.MODULE_DIR.value = "/run/current-system/kernel-modules/lib/modules"; };