-
-
Notifications
You must be signed in to change notification settings - Fork 14.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
stdenv.mkDerivation: Support argument being a fixed-point function (self: { … }) instead of rec { … } #94198
Conversation
stdenv.mkDerivation normally takes an attrset, which is often defined using `rec { … }` in order to allow attributes such as `version` to be referenced inside of other attributes such as `src`. This causes a problem with `overrideAttrs` where the override needs to deeply override everywhere the modified attributes are referenced. With this change it can now take a fixed-point function of the form `(self: attrs)` where the `self` parameter is the full attrset passed to `mkDerivation`. In the absence of overrides, lookups in `self` behave identically to using `rec { … }`, but if `overrideAttrs` is invoked the `self` attribute contains the modified attributes.
overrideAttrs normally only takes a single `super:` attribute. With this change it can now optionally take `self: super:` instead. This is detected by checking if the result of passing `super` is a function.
This is a demonstration of how it works. The resulting derivation is identical to the original.
My biggest question here is whether this impacts performance. For existing code, this effectively changes If there is a measurable performance difference, the definition of |
My other thought is that overriding derivations is still annoying when dealing with fetchers. It might be nice to introduce something like lib.recursiveUpdateDrvs hello {
version = "2.9";
src.outputHash = "…";
} and it would evaluate to hello.overrideAttrs (super: {
version = "2.9";
src = super.src.overrideAttrs (_: {
outputHash = "…";
});
}) This is less obviously helpful with the current state of nixpkgs, because |
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/avoid-rec-expresions-in-nixpkgs/8293/12 |
I guess a problem with the proposed lib.recursiveUpdateFoo hello {
version = "2.9";
src.sha256 = "…";
} as something that expands to hello.overrideAttrs (super: {
version = "2.9";
src = super.src.override {
sha256 = "…";
};
}) So I'll sit on that thought for a while; it's orthogonal to this PR anyway. |
In your example, hello.overrideAttrs (super: {
version = "2.9";
src = super.src.overrideAttrs (_: {
outputHash = "19qy37gkasc4csb1d3bdiz9snn8mir2p3aj0jgzmfv0r2hi7mfzc";
});
}) the new derivation doesn't have any way to fetch the sources: they must already be there. Doesn't this make the configuration non-reproducible (in the sense that if I haven't downloaded the sources first, I will get an error)? |
@DamienCassou I don't know what you mean. The new derivation inherits the With this PR, this code hello.overrideAttrs (super: {
version = "2.9";
src = super.src.overrideAttrs (_: {
outputHash = "19qy37gkasc4csb1d3bdiz9snn8mir2p3aj0jgzmfv0r2hi7mfzc";
});
}) produces the exact same resulting derivation as this code hello.overrideAttrs (super: {
version = "2.9";
src = fetchurl {
url = "mirror://gnu/hello/hello-2.9.tar.gz";
sha256 = "19qy37gkasc4csb1d3bdiz9snn8mir2p3aj0jgzmfv0r2hi7mfzc";
};
meta = super.meta // {
changelog = "https://git.savannah.gnu.org/cgit/hello.git/plain/NEWS?h=v2.9";
};
}) but it's a lot less code and doesn't require repeating information from the original derivation such as the URL. |
I understand now, thank you. |
This looks like a natural improvement of current mkDerivation. |
I'm not in a position to move this forward, but I would be quite happy to see someone else shepherd this. |
I marked this as stale due to inactivity. → More info |
I've independently come up with the same idea and roughly the same implementation. It is in a mergeable state, adds a |
Motivation for this change
This came out of https://discourse.nixos.org/t/avoid-rec-expresions-in-nixpkgs/8293/6?u=lilyball as a proposed way to avoid using
rec { … }
withmkDerivation
. The problem withrec { … }
is it makes it harder to override, as any reference to an attribute from the set needs to be overridden. In particular,version
tends to be re-used, requiring overriding it in multiple places, especially in the URLs given tosrc
fetchers.The approach taken here is to have
mkDerivation
detect if it's given a function instead of an attrset, and if it is a function, then it makes that function into a fixed point, calling it with aself
value that's the fully-evaluated arguments (not the result ofmkDerivation
, just the arguments given to it). Switching to this style produces no changes in the resulting derivation, so it causes no rebuilds. But what it does is makeoverrideAttrs
easier. Instead of sayingyou can now write
(sadly none of the fetchers I looked at, including
fetchurl
, allow you to override the arguments given to them directly, but overridingoutputHash
works for all the fetchers I inspected (fetchurl
,fetchFromGitHub
, andfetchzip
)).As a second step, this PR also updates
overrideAttrs
to support its argument as eithersuper: { … )}
orself: super: { … }
, in case theoverrideAttrs
expects that it might be further customized and wants to introduce its own self-referential values.This works by passing the
super
value to the argument and checking if it gets a function back; if so, it re-calls the argument withself super
instead. I chose this approach because any existingoverrideAttrs
expects justsuper
and must return an attrset, so if we get a function then it must be the new approach.I also updated the stdenv adapters, though I haven't actually tested them.
TODO
stdenv.mkDerivation
.overrideAttrs
.rec { … }
to this new style.Things done
sandbox
innix.conf
on non-NixOS linux)nix-shell -p nixpkgs-review --run "nixpkgs-review wip"
./result/bin/
)nix path-info -S
before and after)