nixos/switch-to-configuration: Add dry activation scripts

Changed files
+71 -42
nixos
+60 -40
nixos/modules/system/activation/activation-script.nix
···
'';
});
+
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
···
util-linux # needed for mount and mountpoint
];
-
scriptType = with types;
+
scriptType = withDry: with types;
let scriptOptions =
{ deps = mkOption
{ type = types.listOf types.str;
···
text = mkOption
{ 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; });
···
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)
-
}
+
type = types.attrsOf (scriptType true);
+
apply = set: set // {
+
script = systemActivationScript set false;
+
};
+
};
-
# 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
-
'';
-
};
+
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 {
···
idempotent and fast.
'';
-
type = with types; attrsOf scriptType;
+
type = with types; attrsOf (scriptType false);
apply = set: {
script = ''
+6
nixos/modules/system/activation/switch-to-configuration.pl
···
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
···
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;
+5 -2
nixos/modules/system/activation/top-level.nix
···
''}
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
···
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;