diff --git a/config.nix b/config.nix index 6e79397..37a9b8f 100644 --- a/config.nix +++ b/config.nix @@ -8,10 +8,11 @@ let modules = [ config ./modules/system.nix + ./modules/system/activation-scripts.nix + ./modules/system/etc.nix ./modules/environment.nix ./modules/launchd ./modules/tmux.nix - ]; }; diff --git a/modules/system.nix b/modules/system.nix index e80f4c9..9435f92 100644 --- a/modules/system.nix +++ b/modules/system.nix @@ -6,35 +6,9 @@ let cfg = config.system; - script = - { config, name, ... }: - { options = { - text = mkOption { - type = types.nullOr types.lines; - default = null; - description = "Text of the file."; - }; - source = mkOption { - type = types.path; - description = "Path of the source file."; - }; +in - deps = mkOption { - type = types.listOf types.str; - default = []; - }; - }; - config = { - source = pkgs.writeScript "activate-${name}" '' - #! ${pkgs.stdenv.shell} - - #### Activation script snippet ${name}: - ${config.text} - ''; - }; - }; - -in { +{ options = { system.build = mkOption { @@ -58,49 +32,10 @@ in { default = "16.09"; }; - system.activationScripts = mkOption { - internal = true; - type = types.attrsOf (types.submodule script); - default = {}; - description = '' - A set of shell script fragments that are executed when a NixOS - system configuration is activated. Examples are updating - /etc, creating accounts, and so on. Since these are executed - every time you boot the system or run - nixos-rebuild, it's important that they are - idempotent and fast. - ''; - }; - }; config = { - system.activationScripts.script.text = '' - #! ${pkgs.stdenv.shell} - - systemConfig=@out@ - - _status=0 - trap "_status=1" ERR - - # Ensure a consistent umask. - umask 0022 - - # Make this configuration the current configuration. - # The readlink is there to ensure that when $systemConfig = /system - # (which is a symlink to the store), /run/current-system is still - # used as a garbage collection root. - ln -sfn "$(readlink -f "$systemConfig")" /run/current-system - - # Prevent the current configuration from being garbage-collected. - ln -sfn /run/current-system /nix/var/nix/gcroots/current-system - - ${cfg.activationScripts.etc.text} - - exit $_status - ''; - system.build.toplevel = pkgs.stdenvNoCC.mkDerivation { name = "nixdarwin-system-${cfg.nixdarwinLabel}"; preferLocalBuild = true; diff --git a/modules/system/activation-scripts.nix b/modules/system/activation-scripts.nix new file mode 100644 index 0000000..1efe201 --- /dev/null +++ b/modules/system/activation-scripts.nix @@ -0,0 +1,63 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.system; + + script = import ./write-text.nix { + inherit lib; + mkTextDerivation = name: text: pkgs.writeScript "activate-${name}" text; + }; + +in + +{ + options = { + + system.activationScripts = mkOption { + internal = true; + type = types.attrsOf (types.submodule script); + default = {}; + description = '' + A set of shell script fragments that are executed when a NixOS + system configuration is activated. Examples are updating + /etc, creating accounts, and so on. Since these are executed + every time you boot the system or run + nixos-rebuild, it's important that they are + idempotent and fast. + ''; + }; + + }; + + config = { + + system.activationScripts.script.text = '' + #! ${pkgs.stdenv.shell} + + systemConfig=@out@ + + _status=0 + trap "_status=1" ERR + + # Ensure a consistent umask. + umask 0022 + + # Make this configuration the current configuration. + # The readlink is there to ensure that when $systemConfig = /system + # (which is a symlink to the store), /run/current-system is still + # used as a garbage collection root. + ln -sfn "$(readlink -f "$systemConfig")" /run/current-system + + # Prevent the current configuration from being garbage-collected. + ln -sfn /run/current-system /nix/var/nix/gcroots/current-system + + ${cfg.activationScripts.etc.text} + + exit $_status + ''; + + }; +} diff --git a/modules/system/etc.nix b/modules/system/etc.nix new file mode 100644 index 0000000..9999c1e --- /dev/null +++ b/modules/system/etc.nix @@ -0,0 +1,63 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + text = import ./write-text.nix { + inherit lib; + mkTextDerivation = name: text: pkgs.writeText "etc-${name}" text; + }; + + etc = filter (f: f.enable) (attrValues config.environment.etc); + +in + +{ + options = { + + environment.etc = mkOption { + type = types.loaOf (types.submodule text); + default = {}; + description = '' + Set of files that have to be linked in /etc. + ''; + }; + + }; + + config = { + + system.build.etc = pkgs.runCommand "etc" {} '' + mkdir -p $out/etc + cd $out/etc + ${concatMapStringsSep "\n" (attr: "ln -s '${attr.source}' '${attr.target}'") etc} + ''; + + system.activationScripts.etc.text = '' + # Set up the statically computed bits of /etc. + echo "setting up /etc..." + + ln -sfn "$(readlink -f $systemConfig/etc)" /etc/static + + for link in $(ls /etc/static/); do + if [ -e "/etc/$link" ]; then + if [ ! -L "/etc/$link" ]; then + echo "warning: /etc/$link is a file, skipping..." >&2 + fi + else + ln -sfn "/etc/static/$link" "/etc/$link" + fi + done + + for link in $(find /etc/ -maxdepth 1 -type l); do + if [[ "$(readlink $link)" == /etc/static/* ]]; then + if [ ! -e "$(readlink -f $link)" ]; then + rm $link + fi + fi + done + ''; + + }; +} diff --git a/modules/system/write-text.nix b/modules/system/write-text.nix new file mode 100644 index 0000000..f15fedd --- /dev/null +++ b/modules/system/write-text.nix @@ -0,0 +1,56 @@ +{ lib, mkTextDerivation }: + +with lib; + +{ config, name, ... }: +let + + sourceDrv = mkTextDerivation name config.text; + +in + +{ + options = { + + enable = mkOption { + type = types.bool; + default = true; + description = '' + Whether this /etc file should be generated. This + option allows specific /etc files to be disabled. + ''; + }; + + text = mkOption { + default = null; + type = types.nullOr types.lines; + description = '' + Text of the file. + ''; + }; + + target = mkOption { + type = types.str; + default = name; + description = '' + Name of symlink (relative to + /etc). Defaults to the attribute + name. + ''; + }; + + source = mkOption { + type = types.path; + description = '' + Path of the source file. + ''; + }; + + }; + + config = { + + source = mkIf (config.text != null) (mkDefault sourceDrv); + + }; +}