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, callPackage }:
stdenv.mkDerivation (self: { 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` ### 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 ```nix
mkDerivation (self: { mkDerivation (self: {
@ -331,9 +331,14 @@ mkDerivation (self: {
``` ```
Note that this does not use the `rec` keyword to reuse `withFeature` in `configureFlags`. 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` Instead, the definition references `self`, allowing users to change `withFeature`
consistently with `overrideAttrs`. 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 Let's look at a more elaborate example to understand the differences between
various bindings: various bindings:
@ -347,11 +352,11 @@ let pkg =
packages = []; packages = [];
# `passthru.tests` is a commonly defined attribute. # `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 # An example of an attribute containing a function
passthru.appendPackages = packages': passthru.appendPackages = packages':
self.overrideAttrs (newSelf: super: { self.public.overrideAttrs (newSelf: super: {
packages = super.packages ++ packages'; packages = super.packages ++ packages';
}); });
@ -363,9 +368,7 @@ let pkg =
in 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`. 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`.
This is also different from `mkDerivation rec { ..... }`, which binds the recursive references immediately, so it allows you to reference original _inputs_ only.
See also the section about [`passthru.tests`](#var-meta-tests). 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; (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; { meta = with lib; {
description = "A program that produces a familiar, friendly greeting"; description = "A program that produces a familiar, friendly greeting";

View file

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