stdenv.mkDerivation: Make self more overlay-like; use self.public

`self` is now arguments, like `super`. The final package is in
`self.public`.
This commit is contained in:
Robert Hensing 2021-07-29 13:09:27 +02:00
parent 2f21bc2fdb
commit 6d7efb3a16
4 changed files with 49 additions and 48 deletions

View file

@ -187,7 +187,7 @@ all places.
{ stdenv, callPackage }:
stdenv.mkDerivation (self: {
# ...
passthru.tests.example = callPackage ./example.nix { my-package = self; };
passthru.tests.example = callPackage ./example.nix { my-package = self.public; }
})
```

View file

@ -319,7 +319,7 @@ For information about how to run the updates, execute `nix-shell maintainers/scr
### Recursive attributes in `mkDerivation`
If you pass a function to `mkDerivation`, it will receive as its argument the final output of the same `mkDerivation` call. For example:
If you pass a function to `mkDerivation`, it will receive as its argument the final arguments, considering use of `overrideAttrs`. For example:
```nix
mkDerivation (self: {
@ -331,9 +331,14 @@ mkDerivation (self: {
```
Note that this does not use the `rec` keyword to reuse `withFeature` in `configureFlags`.
The `rec` keyword works at the syntax level and is unaware of overriding.
Instead, the definition references `self`, allowing users to change `withFeature`
consistently with `overrideAttrs`.
`self` also contains the attribute `public`, which represents the final package,
including the output paths, etc.
Let's look at a more elaborate example to understand the differences between
various bindings:
@ -347,11 +352,11 @@ let pkg =
packages = [];
# `passthru.tests` is a commonly defined attribute.
passthru.tests.simple = f self;
passthru.tests.simple = f self.public;
# An example of an attribute containing a function
passthru.appendPackages = packages':
self.overrideAttrs (newSelf: super: {
self.public.overrideAttrs (newSelf: super: {
packages = super.packages ++ packages';
});
@ -363,9 +368,7 @@ let pkg =
in pkg
```
Unlike the `pkg` binding in the above example, the `self` parameter always references the final package. For instance `(pkg.overrideAttrs(x)).self` is identical to `pkg.overrideAttrs(x)`, whereas `(pkg.overrideAttrs(x)).original` is the same as `pkg`.
This is also different from `mkDerivation rec { ..... }`, which binds the recursive references immediately, so it allows you to reference original _inputs_ only.
Unlike the `pkg` binding in the above example, the `self` parameter always references the final attributes. For instance `(pkg.overrideAttrs(x)).self.public` is identical to `pkg.overrideAttrs(x)`, whereas `(pkg.overrideAttrs(x)).original` is the same as `pkg`.
See also the section about [`passthru.tests`](#var-meta-tests).

View file

@ -28,7 +28,7 @@ stdenv.mkDerivation (self: {
(nixos { environment.noXlibs = true; }).pkgs.hello;
};
passthru.tests.run = callPackage ./test.nix { hello = self; };
passthru.tests.run = callPackage ./test.nix { hello = self.public; };
meta = with lib; {
description = "A program that produces a familiar, friendly greeting";

View file

@ -17,52 +17,50 @@ let
else makeDerivationExtensibleConst mkDerivationSimple fnOrAttrs;
# Based off lib.makeExtensible, with modifications:
# - lib.fix' -> lib.fix ∘ mkDerivationSimple; then inline fix
# - convert `f` to an overlay
# - inline overrideAttrs and make it positional instead of // to reduce allocs
makeDerivationExtensible = mkDerivationSimple: rattrs:
let
r = mkDerivationSimple
(f0:
let
f = self: super:
# Convert f0 to an overlay. Legacy is:
# overrideAttrs (super: {})
# We want to introduce self. We follow the convention of overlays:
# overrideAttrs (self: super: {})
# Which means the first parameter can be either self or super.
# This is surprising, but far better than the confusion that would
# arise from flipping an overlay's parameters in some cases.
let x = f0 super;
in
if builtins.isFunction x
then
# Can't reuse `x`, because `self` comes first.
# Looks inefficient, but `f0 super` was a cheap thunk.
f0 self super
else x;
in
makeDerivationExtensible mkDerivationSimple
(self: let super = rattrs self; in super // f self super))
(rattrs r);
in r;
args = rattrs (args // { inherit public; });
public =
mkDerivationSimple
(f0:
let
f = self: super:
# Convert f0 to an overlay. Legacy is:
# overrideAttrs (super: {})
# We want to introduce self. We follow the convention of overlays:
# overrideAttrs (self: super: {})
# Which means the first parameter can be either self or super.
# This is surprising, but far better than the confusion that would
# arise from flipping an overlay's parameters in some cases.
let x = f0 super;
in
if builtins.isFunction x
then
# Can't reuse `x`, because `self` comes first.
# Looks inefficient, but `f0 super` was a cheap thunk.
f0 self super
else x;
in
makeDerivationExtensible mkDerivationSimple
(self: let super = rattrs self; in super // f self super))
args;
in public;
# makeDerivationExtensibleConst == makeDerivationExtensible (_: attrs),
# but pre-evaluated for a slight improvement in performance.
makeDerivationExtensibleConst = mkDerivationSimple: attrs:
mkDerivationSimple (f0:
let
f = self: super:
let x = f0 super;
in
if builtins.isFunction x
then
# Can't reuse `x`, because `self` comes first.
# Looks inefficient, but `f0 super` was a cheap thunk.
f0 self super
else x;
in
makeDerivationExtensible mkDerivationSimple (self: attrs // f self attrs))
mkDerivationSimple
(f0:
let
f = self: super:
let x = f0 super;
in
if builtins.isFunction x
then
f0 self super
else x;
in
makeDerivationExtensible mkDerivationSimple (self: attrs // f self attrs))
attrs;
in