From 11c20cd39099033adec0688aa44cf2f95f28b1ff Mon Sep 17 00:00:00 2001 From: Yueh-Shun Li Date: Thu, 4 Jul 2024 20:37:01 +0000 Subject: [PATCH] lib.toExtension: init Co-authored-by: Robert Hensing --- lib/default.nix | 3 ++- lib/fixed-points.nix | 64 ++++++++++++++++++++++++++++++++++++++++++++ lib/tests/misc.nix | 17 ++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/lib/default.nix b/lib/default.nix index 0ff3a3980745..4d0035945aaa 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -79,7 +79,8 @@ let fromHexString toHexString toBaseDigits inPureEvalMode isBool isInt pathExists genericClosure readFile; inherit (self.fixedPoints) fix fix' converge extends composeExtensions - composeManyExtensions makeExtensible makeExtensibleWithCustomName; + composeManyExtensions makeExtensible makeExtensibleWithCustomName + toExtension; inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath getAttrFromPath attrVals attrNames attrValues getAttrs catAttrs filterAttrs filterAttrsRecursive foldlAttrs foldAttrs collect nameValuePair mapAttrs diff --git a/lib/fixed-points.nix b/lib/fixed-points.nix index c8d2d1f03acb..ecacddadb94b 100644 --- a/lib/fixed-points.nix +++ b/lib/fixed-points.nix @@ -438,4 +438,68 @@ rec { ${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs); } ); + + /** + Convert to an extending function (overlay). + + `toExtension` is the `toFunction` for extending functions (a.k.a. extensions or overlays). + It converts a non-function or a single-argument function to an extending function, + while returning a double-argument function as-is. + + That is, it takes one of `x`, `prev: x`, or `final: prev: x`, + and returns `final: prev: x`, where `x` is not a function. + + This function is extracted from the implementation of + the fixed-point arguments support of `stdenv.mkDerivation`. + It bridges the gap between `.overrideAttrs` + before and after the overlay-style support, + as well as `config.packageOverrides` and `config.overlays` in `pkgs`. + + # Inputs + + `f` + : The function or non-function to convert to an extending function. + + # Type + + ``` + toExtension ::: (a | a -> a | a -> a -> a) -> a -> a -> a + a = AttrSet & !Function + ``` + + # Examples + :::{.example} + ## `lib.fixedPoints.toExtension` usage example + + ```nix + fix (final: { a = 0; c = final.a; }) + => { a = 0; c = 0; }; + + fix (extends (toExtension { a = 1; b = 2; }) (final: { a = 0; c = final.a; })) + => { a = 1; b = 2; c = 1; }; + + fix (extends (toExtension (prev: { a = 1; b = prev.a; })) (final: { a = 0; c = final.a; })) + => { a = 1; b = 0; c = 1; }; + + fix (extends (toExtension (final: prev: { a = 1; b = prev.a; c = final.a + 1 })) (final: { a = 0; c = final.a; })) + => { a = 1; b = 0; c = 2; }; + ``` + ::: + */ + toExtension = + f: + if lib.isFunction f then + final: prev: + let + fPrev = f prev; + in + if lib.isFunction fPrev then + # f is (final: prev: { ... }) + f final prev + else + # f is (prev: { ... }) + fPrev + else + # f is { ... } + final: prev: f; } diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 06df9fb02ec7..116d86cdfb3f 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -45,6 +45,7 @@ let const escapeXML evalModules + extends filter fix fold @@ -102,6 +103,7 @@ let take testAllTrue toBaseDigits + toExtension toHexString fromHexString toInt @@ -1239,6 +1241,21 @@ runTests { expected = {a = "a";}; }; + testToExtension = { + expr = [ + (fix (final: { a = 0; c = final.a; })) + (fix (extends (toExtension { a = 1; b = 2; }) (final: { a = 0; c = final.a; }))) + (fix (extends (toExtension (prev: { a = 1; b = prev.a; })) (final: { a = 0; c = final.a; }))) + (fix (extends (toExtension (final: prev: { a = 1; b = prev.a; c = final.a + 1; })) (final: { a = 0; c = final.a; }))) + ]; + expected = [ + { a = 0; c = 0; } + { a = 1; b = 2; c = 1; } + { a = 1; b = 0; c = 1; } + { a = 1; b = 0; c = 2; } + ]; + }; + # GENERATORS # these tests assume attributes are converted to lists # in alphabetical order