diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix
index 3a6930314b1a..548b4de852b7 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
+ NIXOS_ACTION being set to dry-activate
+ . 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 dd391c8b5d78..b7a062755296 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 d3e4923a993f..80835d9688f2 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;