summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/default.nix3
-rw-r--r--lib/fixed-points.nix64
-rw-r--r--lib/tests/misc.nix17
3 files changed, 83 insertions, 1 deletions
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 `<pkg>.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