Merge pull request #283547 from r-vdp/boot_sort_key
This commit is contained in:
commit
4ee410d8f8
3 changed files with 88 additions and 24 deletions
|
@ -43,6 +43,7 @@ class BootSpec:
|
||||||
system: str
|
system: str
|
||||||
toplevel: str
|
toplevel: str
|
||||||
specialisations: Dict[str, "BootSpec"]
|
specialisations: Dict[str, "BootSpec"]
|
||||||
|
sortKey: str
|
||||||
initrdSecrets: str | None = None
|
initrdSecrets: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,6 +74,7 @@ def system_dir(profile: str | None, generation: int, specialisation: str | None)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
BOOT_ENTRY = """title {title}
|
BOOT_ENTRY = """title {title}
|
||||||
|
sort-key {sort_key}
|
||||||
version Generation {generation} {description}
|
version Generation {generation} {description}
|
||||||
linux {kernel}
|
linux {kernel}
|
||||||
initrd {initrd}
|
initrd {initrd}
|
||||||
|
@ -123,7 +125,13 @@ def get_bootspec(profile: str | None, generation: int) -> BootSpec:
|
||||||
def bootspec_from_json(bootspec_json: Dict) -> BootSpec:
|
def bootspec_from_json(bootspec_json: Dict) -> BootSpec:
|
||||||
specialisations = bootspec_json['org.nixos.specialisation.v1']
|
specialisations = bootspec_json['org.nixos.specialisation.v1']
|
||||||
specialisations = {k: bootspec_from_json(v) for k, v in specialisations.items()}
|
specialisations = {k: bootspec_from_json(v) for k, v in specialisations.items()}
|
||||||
return BootSpec(**bootspec_json['org.nixos.bootspec.v1'], specialisations=specialisations)
|
systemdBootExtension = bootspec_json.get('org.nixos.systemd-boot', {})
|
||||||
|
sortKey = systemdBootExtension.get('sortKey', 'nixos')
|
||||||
|
return BootSpec(
|
||||||
|
**bootspec_json['org.nixos.bootspec.v1'],
|
||||||
|
specialisations=specialisations,
|
||||||
|
sortKey=sortKey
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def copy_from_file(file: str, dry_run: bool = False) -> str:
|
def copy_from_file(file: str, dry_run: bool = False) -> str:
|
||||||
|
@ -170,6 +178,7 @@ def write_entry(profile: str | None, generation: int, specialisation: str | None
|
||||||
|
|
||||||
with open(tmp_path, 'w') as f:
|
with open(tmp_path, 'w') as f:
|
||||||
f.write(BOOT_ENTRY.format(title=title,
|
f.write(BOOT_ENTRY.format(title=title,
|
||||||
|
sort_key=bootspec.sortKey,
|
||||||
generation=generation,
|
generation=generation,
|
||||||
kernel=kernel,
|
kernel=kernel,
|
||||||
initrd=initrd,
|
initrd=initrd,
|
||||||
|
|
|
@ -87,6 +87,16 @@ in {
|
||||||
|
|
||||||
imports =
|
imports =
|
||||||
[ (mkRenamedOptionModule [ "boot" "loader" "gummiboot" "enable" ] [ "boot" "loader" "systemd-boot" "enable" ])
|
[ (mkRenamedOptionModule [ "boot" "loader" "gummiboot" "enable" ] [ "boot" "loader" "systemd-boot" "enable" ])
|
||||||
|
(lib.mkChangedOptionModule
|
||||||
|
[ "boot" "loader" "systemd-boot" "memtest86" "entryFilename" ]
|
||||||
|
[ "boot" "loader" "systemd-boot" "memtest86" "sortKey" ]
|
||||||
|
(config: lib.strings.removeSuffix ".conf" config.boot.loader.systemd-boot.memtest86.entryFilename)
|
||||||
|
)
|
||||||
|
(lib.mkChangedOptionModule
|
||||||
|
[ "boot" "loader" "systemd-boot" "netbootxyz" "entryFilename" ]
|
||||||
|
[ "boot" "loader" "systemd-boot" "netbootxyz" "sortKey" ]
|
||||||
|
(config: lib.strings.removeSuffix ".conf" config.boot.loader.systemd-boot.netbootxyz.entryFilename)
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
options.boot.loader.systemd-boot = {
|
options.boot.loader.systemd-boot = {
|
||||||
|
@ -102,6 +112,35 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sortKey = mkOption {
|
||||||
|
default = "nixos";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
The sort key used for the NixOS bootloader entries.
|
||||||
|
This key determines sorting relative to non-NixOS entries.
|
||||||
|
See also https://uapi-group.org/specifications/specs/boot_loader_specification/#sorting
|
||||||
|
|
||||||
|
This option can also be used to control the sorting of NixOS specialisations.
|
||||||
|
|
||||||
|
By default, specialisations inherit the sort key of their parent generation
|
||||||
|
and will have the same value for both the sort-key and the version (i.e. the generation number),
|
||||||
|
systemd-boot will therefore sort them based on their file name, meaning that
|
||||||
|
in your boot menu you will have each main generation directly followed by
|
||||||
|
its specialisations sorted alphabetically by their names.
|
||||||
|
|
||||||
|
If you want a different ordering for a specialisation, you can override
|
||||||
|
its sort-key which will cause the specialisation to be uncoupled from its
|
||||||
|
parent generation. It will then be sorted by its new sort-key just like
|
||||||
|
any other boot entry.
|
||||||
|
|
||||||
|
The sort-key is stored in the generation's bootspec, which means that
|
||||||
|
generations keep their sort-keys even if the original definition of the
|
||||||
|
generation was removed from the NixOS configuration.
|
||||||
|
It also means that updating the sort-key will only affect new generations,
|
||||||
|
while old ones will keep the sort-key that they were originally built with.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
editor = mkOption {
|
editor = mkOption {
|
||||||
default = true;
|
default = true;
|
||||||
|
|
||||||
|
@ -184,13 +223,15 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
entryFilename = mkOption {
|
sortKey = mkOption {
|
||||||
default = "memtest86.conf";
|
default = "o_memtest86";
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = lib.mdDoc ''
|
description = lib.mdDoc ''
|
||||||
`systemd-boot` orders the menu entries by the config file names,
|
`systemd-boot` orders the menu entries by their sort keys,
|
||||||
so if you want something to appear after all the NixOS entries,
|
so if you want something to appear after all the NixOS entries,
|
||||||
it should start with {file}`o` or onwards.
|
it should start with {file}`o` or onwards.
|
||||||
|
|
||||||
|
See also {option}`boot.loader.systemd-boot.sortKey`.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -207,13 +248,15 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
entryFilename = mkOption {
|
sortKey = mkOption {
|
||||||
default = "o_netbootxyz.conf";
|
default = "o_netbootxyz";
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = lib.mdDoc ''
|
description = lib.mdDoc ''
|
||||||
`systemd-boot` orders the menu entries by the config file names,
|
`systemd-boot` orders the menu entries by their sort keys,
|
||||||
so if you want something to appear after all the NixOS entries,
|
so if you want something to appear after all the NixOS entries,
|
||||||
it should start with {file}`o` or onwards.
|
it should start with {file}`o` or onwards.
|
||||||
|
|
||||||
|
See also {option}`boot.loader.systemd-boot.sortKey`.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -225,6 +268,7 @@ in {
|
||||||
{ "memtest86.conf" = '''
|
{ "memtest86.conf" = '''
|
||||||
title Memtest86+
|
title Memtest86+
|
||||||
efi /efi/memtest86/memtest.efi
|
efi /efi/memtest86/memtest.efi
|
||||||
|
sort-key z_memtest
|
||||||
'''; }
|
'''; }
|
||||||
'';
|
'';
|
||||||
description = lib.mdDoc ''
|
description = lib.mdDoc ''
|
||||||
|
@ -233,9 +277,10 @@ in {
|
||||||
Each attribute name denotes the destination file name,
|
Each attribute name denotes the destination file name,
|
||||||
and the corresponding attribute value is the contents of the entry.
|
and the corresponding attribute value is the contents of the entry.
|
||||||
|
|
||||||
`systemd-boot` orders the menu entries by the config file names,
|
To control the ordering of the entry in the boot menu, use the sort-key
|
||||||
so if you want something to appear after all the NixOS entries,
|
field, see
|
||||||
it should start with {file}`o` or onwards.
|
https://uapi-group.org/specifications/specs/boot_loader_specification/#sorting
|
||||||
|
and {option}`boot.loader.systemd-boot.sortKey`.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -328,19 +373,25 @@ in {
|
||||||
|
|
||||||
boot.loader.systemd-boot.extraEntries = mkMerge [
|
boot.loader.systemd-boot.extraEntries = mkMerge [
|
||||||
(mkIf cfg.memtest86.enable {
|
(mkIf cfg.memtest86.enable {
|
||||||
"${cfg.memtest86.entryFilename}" = ''
|
"memtest86.conf" = ''
|
||||||
title Memtest86+
|
title Memtest86+
|
||||||
efi /efi/memtest86/memtest.efi
|
efi /efi/memtest86/memtest.efi
|
||||||
|
sort-key ${cfg.memtest86.sortKey}
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
(mkIf cfg.netbootxyz.enable {
|
(mkIf cfg.netbootxyz.enable {
|
||||||
"${cfg.netbootxyz.entryFilename}" = ''
|
"netbootxyz.conf" = ''
|
||||||
title netboot.xyz
|
title netboot.xyz
|
||||||
efi /efi/netbootxyz/netboot.xyz.efi
|
efi /efi/netbootxyz/netboot.xyz.efi
|
||||||
|
sort-key ${cfg.netbootxyz.sortKey}
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
|
boot.bootspec.extensions."org.nixos.systemd-boot" = {
|
||||||
|
inherit (config.boot.loader.systemd-boot) sortKey;
|
||||||
|
};
|
||||||
|
|
||||||
system = {
|
system = {
|
||||||
build.installBootLoader = finalSystemdBootBuilder;
|
build.installBootLoader = finalSystemdBootBuilder;
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,7 @@ in
|
||||||
machine.wait_for_unit("multi-user.target")
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf")
|
machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf")
|
||||||
|
machine.succeed("grep 'sort-key nixos' /boot/loader/entries/nixos-generation-1.conf")
|
||||||
|
|
||||||
# Ensure we actually booted using systemd-boot
|
# Ensure we actually booted using systemd-boot
|
||||||
# Magic number is the vendor UUID used by systemd-boot.
|
# Magic number is the vendor UUID used by systemd-boot.
|
||||||
|
@ -166,7 +167,9 @@ in
|
||||||
|
|
||||||
nodes.machine = { pkgs, lib, ... }: {
|
nodes.machine = { pkgs, lib, ... }: {
|
||||||
imports = [ common ];
|
imports = [ common ];
|
||||||
specialisation.something.configuration = {};
|
specialisation.something.configuration = {
|
||||||
|
boot.loader.systemd-boot.sortKey = "something";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = ''
|
testScript = ''
|
||||||
|
@ -179,6 +182,9 @@ in
|
||||||
machine.succeed(
|
machine.succeed(
|
||||||
"grep -q 'title NixOS (something)' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
|
"grep -q 'title NixOS (something)' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
|
||||||
)
|
)
|
||||||
|
machine.succeed(
|
||||||
|
"grep 'sort-key something' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
|
||||||
|
)
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -256,25 +262,25 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = ''
|
testScript = ''
|
||||||
machine.succeed("test -e /boot/loader/entries/o_netbootxyz.conf")
|
machine.succeed("test -e /boot/loader/entries/netbootxyz.conf")
|
||||||
machine.succeed("test -e /boot/efi/netbootxyz/netboot.xyz.efi")
|
machine.succeed("test -e /boot/efi/netbootxyz/netboot.xyz.efi")
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
entryFilename = makeTest {
|
memtestSortKey = makeTest {
|
||||||
name = "systemd-boot-entry-filename";
|
name = "systemd-boot-memtest-sortkey";
|
||||||
meta.maintainers = with pkgs.lib.maintainers; [ Enzime julienmalka ];
|
meta.maintainers = with pkgs.lib.maintainers; [ Enzime julienmalka ];
|
||||||
|
|
||||||
nodes.machine = { pkgs, lib, ... }: {
|
nodes.machine = { pkgs, lib, ... }: {
|
||||||
imports = [ common ];
|
imports = [ common ];
|
||||||
boot.loader.systemd-boot.memtest86.enable = true;
|
boot.loader.systemd-boot.memtest86.enable = true;
|
||||||
boot.loader.systemd-boot.memtest86.entryFilename = "apple.conf";
|
boot.loader.systemd-boot.memtest86.sortKey = "apple";
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = ''
|
testScript = ''
|
||||||
machine.fail("test -e /boot/loader/entries/memtest86.conf")
|
machine.succeed("test -e /boot/loader/entries/memtest86.conf")
|
||||||
machine.succeed("test -e /boot/loader/entries/apple.conf")
|
|
||||||
machine.succeed("test -e /boot/efi/memtest86/memtest.efi")
|
machine.succeed("test -e /boot/efi/memtest86/memtest.efi")
|
||||||
|
machine.succeed("grep 'sort-key apple' /boot/loader/entries/memtest86.conf")
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -285,7 +291,6 @@ in
|
||||||
nodes.machine = { pkgs, lib, ... }: {
|
nodes.machine = { pkgs, lib, ... }: {
|
||||||
imports = [ commonXbootldr ];
|
imports = [ commonXbootldr ];
|
||||||
boot.loader.systemd-boot.memtest86.enable = true;
|
boot.loader.systemd-boot.memtest86.enable = true;
|
||||||
boot.loader.systemd-boot.memtest86.entryFilename = "apple.conf";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = { nodes, ... }: ''
|
testScript = { nodes, ... }: ''
|
||||||
|
@ -295,8 +300,7 @@ in
|
||||||
machine.wait_for_unit("multi-user.target")
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
machine.succeed("test -e /efi/EFI/systemd/systemd-bootx64.efi")
|
machine.succeed("test -e /efi/EFI/systemd/systemd-bootx64.efi")
|
||||||
machine.fail("test -e /boot/loader/entries/memtest86.conf")
|
machine.succeed("test -e /boot/loader/entries/memtest86.conf")
|
||||||
machine.succeed("test -e /boot/loader/entries/apple.conf")
|
|
||||||
machine.succeed("test -e /boot/EFI/memtest86/memtest.efi")
|
machine.succeed("test -e /boot/EFI/memtest86/memtest.efi")
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
@ -388,9 +392,9 @@ in
|
||||||
machine.succeed("${finalSystem}/bin/switch-to-configuration boot")
|
machine.succeed("${finalSystem}/bin/switch-to-configuration boot")
|
||||||
machine.fail("test -e /boot/efi/fruits/tomato.efi")
|
machine.fail("test -e /boot/efi/fruits/tomato.efi")
|
||||||
machine.fail("test -e /boot/efi/nixos/.extra-files/efi/fruits/tomato.efi")
|
machine.fail("test -e /boot/efi/nixos/.extra-files/efi/fruits/tomato.efi")
|
||||||
machine.succeed("test -e /boot/loader/entries/o_netbootxyz.conf")
|
machine.succeed("test -e /boot/loader/entries/netbootxyz.conf")
|
||||||
machine.succeed("test -e /boot/efi/netbootxyz/netboot.xyz.efi")
|
machine.succeed("test -e /boot/efi/netbootxyz/netboot.xyz.efi")
|
||||||
machine.succeed("test -e /boot/efi/nixos/.extra-files/loader/entries/o_netbootxyz.conf")
|
machine.succeed("test -e /boot/efi/nixos/.extra-files/loader/entries/netbootxyz.conf")
|
||||||
machine.succeed("test -e /boot/efi/nixos/.extra-files/efi/netbootxyz/netboot.xyz.efi")
|
machine.succeed("test -e /boot/efi/nixos/.extra-files/efi/netbootxyz/netboot.xyz.efi")
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue