summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nixos/modules/system/activation/activation-script.nix100
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl6
-rw-r--r--nixos/modules/system/activation/top-level.nix7
3 files changed, 71 insertions, 42 deletions
diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix
index 3a6930314b1..548b4de852b 100644
--- a/nixos/modules/system/activation/activation-script.nix
+++ b/nixos/modules/system/activation/activation-script.nix
@@ -17,6 +17,41 @@ let
     '';
   });
 
+  systemActivationScript = set: onlyDry: let
+    set' = filterAttrs (_: v: onlyDry -> v.supportsDryActivation) (mapAttrs (_: v: if isString v then (noDepEntry v) // { supportsDryActivation = false; } else v) set);
+    withHeadlines = addAttributeName set';
+  in
+    ''
+      #!${pkgs.runtimeShell}
+
+      systemConfig='@out@'
+
+      export PATH=/empty
+      for i in ${toString path}; do
+          PATH=$PATH:$i/bin:$i/sbin
+      done
+
+      _status=0
+      trap "_status=1 _localstatus=\$?" ERR
+
+      # Ensure a consistent umask.
+      umask 0022
+
+      ${textClosureMap id (withHeadlines) (attrNames withHeadlines)}
+
+    '' + optionalString (!onlyDry) ''
+      # 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
+
+      exit $_status
+    '';
+
   path = with pkgs; map getBin
     [ coreutils
       gnugrep
@@ -28,7 +63,7 @@ let
       util-linux # needed for mount and mountpoint
     ];
 
-  scriptType = with types;
+  scriptType = withDry: with types;
     let scriptOptions =
       { deps = mkOption
           { type = types.listOf types.str;
@@ -39,6 +74,19 @@ let
           { type = types.lines;
             description = "The content of the script.";
           };
+      } // optionalAttrs withDry {
+        supportsDryActivation = mkOption
+          { type = types.bool;
+            default = false;
+            description = ''
+              Whether this activation script supports being dry-activated.
+              These activation scripts will also be executed on dry-activate
+              activations with the environment variable
+              <literal>NIXOS_ACTION</literal> being set to <literal>dry-activate
+              </literal>.  it's important that these activation scripts  don't
+              modify anything about the system when the variable is set.
+            '';
+          };
       };
     in either str (submodule { options = scriptOptions; });
 
@@ -74,47 +122,19 @@ in
         idempotent and fast.
       '';
 
-      type = types.attrsOf scriptType;
-
-      apply = set: {
-        script =
-          ''
-            #! ${pkgs.runtimeShell}
-
-            systemConfig=@out@
-
-            export PATH=/empty
-            for i in ${toString path}; do
-                PATH=$PATH:$i/bin:$i/sbin
-            done
-
-            _status=0
-            trap "_status=1 _localstatus=\$?" ERR
-
-            # Ensure a consistent umask.
-            umask 0022
-
-            ${
-              let
-                set' = mapAttrs (n: v: if isString v then noDepEntry v else v) set;
-                withHeadlines = addAttributeName set';
-              in textClosureMap id (withHeadlines) (attrNames withHeadlines)
-            }
-
-            # 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
-
-            exit $_status
-          '';
+      type = types.attrsOf (scriptType true);
+      apply = set: set // {
+        script = systemActivationScript set false;
       };
     };
 
+    system.dryActivationScript = mkOption {
+      description = "The shell script that is to be run when dry-activating a system.";
+      readOnly = true;
+      internal = true;
+      default = systemActivationScript (removeAttrs config.system.activationScripts [ "script" ]) true;
+    };
+
     system.userActivationScripts = mkOption {
       default = {};
 
@@ -137,7 +157,7 @@ in
         idempotent and fast.
       '';
 
-      type = with types; attrsOf scriptType;
+      type = with types; attrsOf (scriptType false);
 
       apply = set: {
         script = ''
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index dd391c8b5d7..b7a06275529 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -36,6 +36,8 @@ EOF
     exit 1;
 }
 
+$ENV{NIXOS_ACTION} = $action;
+
 # This is a NixOS installation if it has /etc/NIXOS or a proper
 # /etc/os-release.
 die "This is not a NixOS installation!\n" unless
@@ -360,6 +362,10 @@ if ($action eq "dry-activate") {
         if scalar @unitsToStopFiltered > 0;
     print STDERR "would NOT stop the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n"
         if scalar(keys %unitsToSkip) > 0;
+
+    print STDERR "would activate the configuration...\n";
+    system("$out/dry-activate", "$out");
+
     print STDERR "would restart systemd\n" if $restartSystemd;
     print STDERR "would restart the following units: ", join(", ", sort(keys %unitsToRestart)), "\n"
         if scalar(keys %unitsToRestart) > 0;
diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix
index d3e4923a993..80835d9688f 100644
--- a/nixos/modules/system/activation/top-level.nix
+++ b/nixos/modules/system/activation/top-level.nix
@@ -56,9 +56,11 @@ let
       ''}
 
       echo "$activationScript" > $out/activate
+      echo "$dryActivationScript" > $out/dry-activate
       substituteInPlace $out/activate --subst-var out
-      chmod u+x $out/activate
-      unset activationScript
+      substituteInPlace $out/dry-activate --subst-var out
+      chmod u+x $out/activate $out/dry-activate
+      unset activationScript dryActivationScript
 
       cp ${config.system.build.bootStage2} $out/init
       substituteInPlace $out/init --subst-var-by systemConfig $out
@@ -108,6 +110,7 @@ let
       config.system.build.installBootLoader
       or "echo 'Warning: do not know how to make this configuration bootable; please enable a boot loader.' 1>&2; true";
     activationScript = config.system.activationScripts.script;
+    dryActivationScript = config.system.dryActivationScript;
     nixosLabel = config.system.nixos.label;
 
     configurationName = config.boot.loader.grub.configurationName;