diff --git a/lib/customisation.nix b/lib/customisation.nix index 6159ce8ea27a4..63bea15755aa5 100644 --- a/lib/customisation.nix +++ b/lib/customisation.nix @@ -156,8 +156,25 @@ rec { let # Creates a functor with the same arguments as f mirrorArgs = mirrorFunctionArgs f; + # Recover overrider and additional attributes for f + # When f is a callable attribute set, + # it may contain its own `f.override` and additional attributes. + # This helper function recovers those attributes and decorate the overrider. + recoverMetadata = + if isAttrs f then + fDecorated: + # Preserve additional attributes for f + f + // fDecorated + # Decorate f.override if presented + // lib.optionalAttrs (f ? override) { + override = fdrv: makeOverridable (f.override fdrv); + } + else + id; + decorate = f': recoverMetadata (mirrorArgs f'); in - mirrorArgs ( + decorate ( origArgs: let result = f origArgs; diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index e4f2222b76850..4bf2a215129a7 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -202,6 +202,85 @@ runTests { }; }; + testOverridePreserveFunctionMetadata = + let + toCallableAttrs = f: setFunctionArgs f (functionArgs f); + constructDefinition = + { + a ? 3, + }: + toCallableAttrs ( + { + b ? 5, + }: + { + inherit a b; + } + ) + // { + inherit a; + c = 7; + }; + construct0 = makeOverridable constructDefinition { }; + construct1 = makeOverridable construct0; + construct0p = construct0.override { a = 11; }; + construct1p = construct1.override { a = 11; }; + in + { + expr = { + construct-metadata = { + inherit (construct1) a c; + }; + construct-overridden-metadata = { + v = construct0p.a; + inherit (construct1p) a c; + }; + construct-overridden-result-overrider = { + result-overriders-exist = mapAttrs (_: f: (f { }) ? override) { + inherit construct1 construct1p; + }; + result-overrider-functionality = { + overridden = { + inherit ((construct1p { }).override { b = 13; }) a b; + }; + direct = { + inherit (construct1p { b = 13; }) a b; + }; + v = { + inherit (construct0p { b = 13; }) a b; + }; + }; + }; + }; + expected = { + construct-metadata = { + inherit (construct0) a c; + }; + construct-overridden-metadata = { + v = 11; + inherit (construct0p) a c; + }; + construct-overridden-result-overrider = { + result-overriders-exist = { + construct1 = true; + construct1p = true; + }; + result-overrider-functionality = { + overridden = { + inherit (construct0p { b = 13; }) a b; + }; + direct = { + inherit (construct0p { b = 13; }) a b; + }; + v = { + a = 11; + b = 13; + }; + }; + }; + }; + }; + testCallPackageWithOverridePreservesArguments = let f =