Nix Overrides That Expire Themselves
摘要
作者发布新版 Haskell 包到 Hackage 后,因 nixpkgs 采用滞后,需要在 flake.nix 中写 override 覆盖依赖版本。他介绍了一个同事展示的模式:在 override 里用 lib.versionAtLeast 比较当前 nixpkgs 提供的版本与 override 目标版本,并用 lib.warnIf 在评估时打印警告,当 nixpkgs 版本已不低于 override 版本时提示该 override 已冗余、可以删除。该模式同样适用于清理因包被标记为 broken 而写的 override,当上游修复后 broken 标记移除,警告会自动提醒删除。
荐读理由
正文给出了具体的 Nix 表达式写法:用 lib.versionAtLeast 和 lib.warnIf 在评估期比较版本并输出警告,可立即复制到自己的 flake.nix 中,避免升级 nixpkgs 后遗留无用 override;该条件化警告思路还能推广到 broken 标记等场景,减少维护负担。
原文
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.
这条对你有帮助吗?