Context: Upon discovering that arch-install-scripts
is in nixpkgs
(hooray! most of my machine still run Arch at this point), I’ve decided to replace my somewhat-janky Arch-based rescue USB with a custom NixOS rescue image, complete with a lot of the convenience tools I love like ripgrep
, fd
, neovim
, and tools for working with zfs
, btrfs
, in addition to the usual suspects for a rescue drive. It seems like the NixOS install image is a perfect candidate for a starting place, but I’d like to tweak a few things.
It seems like I’m frequently ending up in this situation of finding an existing bit of code that does almost what I’d want, which in an imperative context would be really easy to sed -i s/foo/bar/
, but in nix I struggle to make this change. It’s simple to override a function’s inputs, but what I usually end up wanting to do is override one of the variables defined in a let
… in
block.
As a very simple example, I’d like to take the static set timeout=10
* in the EFI section of iso-image.nix
(part of efiDir
, which is part of a let
… in
) and decrease it for snappier boot time. I’d also like to change some of the names and titles of boot targets, but we’ll stick with this timeout for demonstration purposes.
One obvious / simple approach is to just copy the whole piece of iso-image.nix
, modify, and import that instead. The obvious disadvantage here would be potentially missing out on updates over time, or becoming out-of-sync with the rest of nixpkgs
. It also seems a bit heavy handed compared to sed 's/\(timeout=\)[0-9]\+/\15/'
.
I thought it might be more “the nix way” to split out the efi
part of isoImage.config.isoImage.contents
, which I think I could then could use in mkDerivation
and put a modified version in $out
and use that instead of iso-image.nix
, or perhaps as some kind of override:
{ modulesPath, config, lib, pkgs, ... }: {
# currently just pulls out `efi` then puts it back
config.isoImage.contents =
let
isoImage = import "${modulesPath}/installer/cd-dvd/iso-image.nix" { inherit config lib pkgs; };
contents = isoImage.config.isoImage.contents;
efi = lib.findSingle (item: (builtins.match "/EFI" item.target != null)) (abort "no EFI match") (abort "multiple EFI matches") contents;
rest = lib.remove efi contents;
in
rest ++ [ efi ];
}
However, I get the feeling that there’s probably an even better or more “nix-like” approach for this type of minor tweak that I’m missing.
- If you wanted to make an image that for the sake of argument was otherwise identical to the default
iso-image.nix
, but withset timeout=2
for EFI, what approach would you take? - If you also wanted a few other minor changes (modify titles, perhaps remove some boot targets) would you be likely to take the same approach?
- Given the general problem of “I don’t want to reinvent the wheel, I hope not to have to modify a bunch of the dependencies or dependents, I just want a minor change to a bit of existing nix code” (perhaps tuning a setting on a config file that for whatever reason isn’t exposed as an input) should I be reading more about overlays, mkDerivation / overrideDerivation + patches, perhaps makeWrapper, something else entirely, or is it just so situation-dependent that there’s no best “try this first” approach?
Thanks for any thoughts and discussion. After a few false starts with nix over the last few years, I think it’s finally sticking.
* BTW, ignoring the seconds vs decisecond discrepancy, does anyone know why this EFI timeout is a static 10 instead of using the same value used to configure the syslinux timeout? Do you think a PR addressing this would be welcome?