Nix Overrides That Expire Themselves
I recently published yesod-form-1.7.10 to Hackage. My project gets all of its
dependencies from nixpkgs, and nixpkgs gradually adopts Haskell packages from
Hackage. That means that there’s some time between when the package lands in
nixpkgs, and when I need to use the package in my project, which is right now.
You can write an override in your flake.nix to get the newer package you
need, but what happens when you eventually bump the nixpkgs version and the
override is made redundant? There’s nothing by default which warns you that the
override should be removed.
A colleague of mine showed me this pattern which makes the override announce its own obsolescence. When Nix evaluates the flake, it compares package versions and warns when the version is greater than or equal to the version in your override.
packageOverrides = prev.lib.composeExtensions prev.haskell.packageOverrides
(hfinal: hprev: {
# we require 1.7.10 for runFormPRG; the pinned nixpkgs only has
# 1.7.9.2.
yesod-form =
let
noOverride =
prev.lib.versionAtLeast hprev.yesod-form.version "1.7.10";
in
prev.lib.warnIf noOverride ''
yesod-form >= 1.7.10 is now in nixpkgs, the override can be removed.
''
(if noOverride then
hprev.yesod-form
else
prev.haskell.lib.dontCheck (hfinal.callHackageDirect
{
pkg = "yesod-form";
ver = "1.7.10";
sha256 = "sha256-9TqA7c2djVaLvrj/rj47LiJ7D1rLbrGhi585FvD9zRE=";
}
{ }));
});
In this example, hprev.yesod-form.version is whatever the pinned nixpkgs
provides. The lib.versionAtLeast function compares version strings, and
lib.warnIf is the part that prints a message during evaluation when the
condition is true.
So, when it’s time to remove the override, you’ll see something like this:
evaluation warning: yesod-form >= 1.7.10 is now in nixpkgs, the override can be removed.
This approach isn’t specific to package versions. You can do this anywhere you have an override where the justification for the override can be expressed conditionally. For example, we also use this to clean up overrides where a package was marked as broken in nixpkgs, and is subsequently un-marked.
markUnbrokenWithWarning = p: nixpkgs.lib.warnIfNot p.meta.broken ''
Package ${p.meta.name} is no longer broken.
The corresponding override can be removed.
''
(markUnbroken p);
When someone eventually fixes the package upstream and the broken flag is
removed, the warning tells us to delete the workaround.