From: Scott Worley Date: Fri, 14 Aug 2026 05:47:28 +0000 (-0700) Subject: Begin X-Git-Url: http://git.scottworley.com/nixos-boot-usage/commitdiff_plain/a47c58267d5b250d6f34d7c1994418135c657713?ds=sidebyside Begin --- a47c58267d5b250d6f34d7c1994418135c657713 diff --git a/modules/boot-usage.nix b/modules/boot-usage.nix new file mode 100644 index 0000000..d30bd9e --- /dev/null +++ b/modules/boot-usage.nix @@ -0,0 +1,76 @@ +{ lib, config, ... }: +{ + options = { + chk.bootDiskUsage = lib.mkOption { + description = '' + Choose boot.*.configurationLimit based on disk usage: Keep adding + entries up to this limit of disk space, in megabytes. + + This allows the boot menu length to shrink and grow depending upon + how much kernel/initrd overlap there is between system profiles. + + Note: This implementation doesn't yet support: + * Named profiles / specialisations + * Devicetrees + * Grub / refind / limine (systemd-boot only) + + ''; + type = with lib.types; nullOr int; + default = null; + }; + boot.loader.systemd-boot.configurationLimit = lib.mkOption { + # Normally, this is inserted into systemd-boot-builder.py like this: + # + # CONFIGURATION_LIMIT = int("@configurationLimit@") + # + # When chk.bootDiskUsage is set, instead of a simple integer constant, + # we instead insert a program snippet to dynamically calculate a + # configurationLimit (boot list length) as large as possible without + # going over the allowed disk space consumption. + # + # * We're stuck in expression context here, so we can't have nice things + # like names; it has to be one giant expression. :( + # * This declaration appears early in systemd-boot-builder.py, so we + # can't use the various helper functions it defines below this point. + # * We can't get access to the output of 'nix-env --list-generations' + # that it runs later, so we have to also run it here. Running it twice + # introduces a TOCTOU race risk, but systemd-boot-builder.py is already + # full of those, so one more doesn't change much. + apply = + prev: + if builtins.isNull (config.chk.bootDiskUsage) then + prev + else + '' + " + ( + "%d" % ( + __import__('functools').reduce( + lambda acc, gen: ( + gen[0] if sum(x[0] for x in acc[1]) < (${toString config.chk.bootDiskUsage} * 1024 * 1024) else acc[0], + acc[1].union(gen[1]) + ), + enumerate( + [[(os.stat(f).st_size, f) for f in gen] + for gen in map( + lambda j: [j["kernel"], j["initrd"]], + reversed( + [json.load( + open(f'/nix/var/nix/profiles/system-{line.split()[0]}-link/boot.json', 'r') + )["org.nixos.bootspec.v1"] + for line in subprocess.run( + ['nix-env', '--list-generations', '-p', '/nix/var/nix/profiles/system'], + check=True, text=True, stdout=subprocess.PIPE, stderr=sys.stderr + ).stdout.split('\n')[:-1] + ] + ) + ) + ], + start=1 + ), + (0, set()) + )[0] + ) + ) + "''; + }; + }; +}