nixos/iso-image: Support specialisations.

This commit is contained in:
Will Fancher
2025-03-16 01:38:37 -04:00
parent 8eb8908837
commit f2204986a7
+145 -80
View File
@@ -8,57 +8,63 @@
...
}:
let
/**
Given a list of `options`, concats the result of mapping each options
to a menuentry for use in grub.
* defaults: {name, image, params, initrd}
* options: [ option... ]
* option: {name, params, class}
*/
# Builds a single menu entry
menuBuilderGrub2 =
defaults: options:
lib.concatStrings (
map (option: ''
menuentry '${defaults.name} ${
# Name appended to menuentry defaults to params if no specific name given.
option.name or (lib.optionalString (option ? params) "(${option.params})")
}' ${lib.optionalString (option ? class) " --class ${option.class}"} {
# Fallback to UEFI console for boot, efifb sometimes has difficulties.
terminal_output console
{
name,
class,
image,
params,
initrd,
}:
''
menuentry '${name}' --class ${class} {
# Fallback to UEFI console for boot, efifb sometimes has difficulties.
terminal_output console
linux ${defaults.image} \''${isoboot} ${defaults.params} ${option.params or ""}
initrd ${defaults.initrd}
}
'') options
);
linux ${image} \''${isoboot} ${params}
initrd ${initrd}
}
'';
/**
Builds the default options.
*/
buildMenuGrub2 = buildMenuAdditionalParamsGrub2 "";
# Builds all menu entries
buildMenuGrub2 =
{
cfg ? config,
params ? [ ],
}:
let
menuConfig = {
name = lib.concatStrings [
cfg.isoImage.prependToMenuLabel
cfg.system.nixos.distroName
" "
cfg.system.nixos.label
cfg.isoImage.appendToMenuLabel
(lib.optionalString (cfg.isoImage.configurationName != null) (" " + cfg.isoImage.configurationName))
];
params = "init=${cfg.system.build.toplevel}/init ${toString cfg.boot.kernelParams} ${toString params}";
image = "/boot/${cfg.boot.kernelPackages.kernel + "/" + cfg.system.boot.loader.kernelFile}";
initrd = "/boot/${cfg.system.build.initialRamdisk + "/" + cfg.system.boot.loader.initrdFile}";
class = "installer";
};
in
''
${lib.optionalString cfg.isoImage.showConfiguration (menuBuilderGrub2 menuConfig)}
${lib.concatStringsSep "\n" (
lib.mapAttrsToList (
specName:
{ configuration, ... }:
buildMenuGrub2 {
cfg = configuration;
inherit params;
}
) cfg.specialisation
)}
'';
targetArch = if config.boot.loader.grub.forcei686 then "ia32" else pkgs.stdenv.hostPlatform.efiArch;
/**
Given params to add to `params`, build a set of default options.
Use this one when creating a variant (e.g. hidpi)
*/
buildMenuAdditionalParamsGrub2 =
additional:
let
finalCfg = {
name = "${config.isoImage.prependToMenuLabel}${config.system.nixos.distroName} ${config.system.nixos.label}${config.isoImage.appendToMenuLabel}";
params = "init=${config.system.build.toplevel}/init ${additional} ${toString config.boot.kernelParams}";
image = "/boot/${config.system.boot.loader.kernelFile}";
initrd = "/boot/initrd";
};
in
menuBuilderGrub2 finalCfg [
{ class = "installer"; }
];
# Timeout in syslinux is in units of 1/10 of a second.
# null means max timeout (35996, just under 1h in 1/10 seconds)
# 0 means disable timeout
@@ -137,13 +143,32 @@ let
# result in incorrect boot entries.
menuBuilderIsolinux =
{ label, params }:
{
cfg ? config,
label,
params ? [ ],
}:
''
LABEL ${label}
MENU LABEL ${config.isoImage.prependToMenuLabel}${config.system.nixos.distroName} ${config.system.nixos.label}${config.isoImage.appendToMenuLabel}
LINUX /boot/${config.system.boot.loader.kernelFile}
APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} ${toString params}
INITRD /boot/${config.system.boot.loader.initrdFile}
${lib.optionalString cfg.isoImage.showConfiguration ''
LABEL ${label}
MENU LABEL ${cfg.isoImage.prependToMenuLabel}${cfg.system.nixos.distroName} ${cfg.system.nixos.label}${cfg.isoImage.appendToMenuLabel}${
lib.optionalString (cfg.isoImage.configurationName != null) (" " + cfg.isoImage.configurationName)
}
LINUX /boot/${cfg.boot.kernelPackages.kernel + "/" + cfg.system.boot.loader.kernelFile}
APPEND init=${cfg.system.build.toplevel}/init ${toString cfg.boot.kernelParams} ${toString params}
INITRD /boot/${cfg.system.build.initialRamdisk + "/" + cfg.system.boot.loader.initrdFile}
''}
${lib.concatStringsSep "\n\n" (
lib.mapAttrsToList (
name: specCfg:
menuBuilderIsolinux {
cfg = specCfg.configuration;
label = "${label}-${name}";
inherit params;
}
) cfg.specialisation
)}
'';
baseIsolinuxCfg = ''
@@ -156,10 +181,7 @@ let
DEFAULT boot
${menuBuilderIsolinux {
label = "boot";
params = [ ];
}}
${menuBuilderIsolinux { label = "boot"; }}
MENU BEGIN Options
@@ -209,6 +231,8 @@ let
grubPkgs = if config.boot.loader.grub.forcei686 then pkgs.pkgsi686Linux else pkgs;
grubMenuCfg = ''
set textmode=${lib.boolToString (config.isoImage.forceTextMode)}
#
# Menu configuration
#
@@ -273,6 +297,20 @@ let
fi
''
}
hiddenentry 'Text mode' --hotkey 't' {
loadfont (\$root)/EFI/BOOT/unicode.pf2
set textmode=true
terminal_output console
}
${lib.optionalString (config.isoImage.grubTheme != null) ''
hiddenentry 'GUI mode' --hotkey 'g' {
$(find ${config.isoImage.grubTheme} -iname '*.pf2' -printf "loadfont (\$root)/EFI/BOOT/grub-theme/%P\n")
set textmode=false
terminal_output gfxterm
}
''}
'';
# The EFI boot image.
@@ -368,7 +406,6 @@ let
cat <<EOF > $out/EFI/BOOT/grub.cfg
set textmode=${lib.boolToString (config.isoImage.forceTextMode)}
set timeout=${toString grubEfiTimeout}
clear
@@ -381,20 +418,6 @@ let
${grubMenuCfg}
hiddenentry 'Text mode' --hotkey 't' {
loadfont (\$root)/EFI/BOOT/unicode.pf2
set textmode=true
terminal_output console
}
${lib.optionalString (config.isoImage.grubTheme != null) ''
hiddenentry 'GUI mode' --hotkey 'g' {
$(find ${config.isoImage.grubTheme} -iname '*.pf2' -printf "loadfont (\$root)/EFI/BOOT/grub-theme/%P\n")
set textmode=false
terminal_output gfxterm
}
''}
# If the parameter iso_path is set, append the findiso parameter to the kernel
# line. We need this to allow the nixos iso to be booted from grub directly.
if [ \''${iso_path} ] ; then
@@ -405,7 +428,7 @@ let
# Menu entries
#
${buildMenuGrub2}
${buildMenuGrub2 { }}
submenu "Options" --class submenu --class hidpi {
${grubMenuCfg}
@@ -418,7 +441,7 @@ let
''
submenu "${title}" --class ${class} {
${grubMenuCfg}
${buildMenuAdditionalParamsGrub2 (toString params)}
${buildMenuGrub2 { inherit params; }}
}
''
) optionsSubMenus}
@@ -721,6 +744,19 @@ in
'';
};
isoImage.configurationName = lib.mkOption {
default = null;
type = lib.types.nullOr lib.types.str;
example = "GNOME";
description = ''
The name of the configuration in the title of the boot entry.
'';
};
isoImage.showConfiguration = lib.mkEnableOption "show this configuration in the menu" // {
default = true;
};
isoImage.forceTextMode = lib.mkOption {
default = false;
type = lib.types.bool;
@@ -806,6 +842,25 @@ in
in
"isoImage.volumeID ${config.isoImage.volumeID} is ${howmany} characters. That is ${toomany} characters longer than the limit of 32.";
}
(
let
badSpecs = lib.filterAttrs (
specName: specCfg: specCfg.configuration.isoImage.volumeID != config.isoImage.volumeID
) config.specialisation;
in
{
assertion = badSpecs == { };
message = ''
All specialisations must use the same 'isoImage.volumeID'.
Specialisations with different volumeIDs:
${lib.concatMapStringsSep "\n" (specName: ''
- ${specName}
'') (builtins.attrNames badSpecs)}
'';
}
)
];
# Don't build the GRUB menu builder script, since we don't need it
@@ -853,20 +908,30 @@ in
# Individual files to be included on the CD, outside of the Nix
# store on the CD.
isoImage.contents =
let
cfgFiles =
cfg:
lib.optionals cfg.isoImage.showConfiguration ([
{
source = cfg.boot.kernelPackages.kernel + "/" + cfg.system.boot.loader.kernelFile;
target = "/boot/" + cfg.boot.kernelPackages.kernel + "/" + cfg.system.boot.loader.kernelFile;
}
{
source = cfg.system.build.initialRamdisk + "/" + cfg.system.boot.loader.initrdFile;
target = "/boot/" + cfg.system.build.initialRamdisk + "/" + cfg.system.boot.loader.initrdFile;
}
])
++ lib.concatLists (
lib.mapAttrsToList (_: { configuration, ... }: cfgFiles configuration) cfg.specialisation
);
in
[
{
source = config.boot.kernelPackages.kernel + "/" + config.system.boot.loader.kernelFile;
target = "/boot/" + config.system.boot.loader.kernelFile;
}
{
source = config.system.build.initialRamdisk + "/" + config.system.boot.loader.initrdFile;
target = "/boot/" + config.system.boot.loader.initrdFile;
}
{
source = pkgs.writeText "version" config.system.nixos.label;
target = "/version.txt";
}
]
++ lib.unique (cfgFiles config)
++ lib.optionals (config.isoImage.makeBiosBootable) [
{
source = config.isoImage.splashImage;