From 97bb209a1a5a4b23578c7d433093fc88cc56220f Mon Sep 17 00:00:00 2001 From: Yueh-Shun Li Date: Fri, 24 Oct 2025 01:55:20 +0800 Subject: [PATCH 1/3] lib.makeOverridable: observe existing overriders in .__overriders --- lib/customisation.nix | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/customisation.nix b/lib/customisation.nix index ce00e364ba76b..02a2a956f41c3 100644 --- a/lib/customisation.nix +++ b/lib/customisation.nix @@ -32,6 +32,8 @@ let extends toFunction id + genAttrs + subtractLists ; inherit (lib.strings) levenshtein levenshteinAtMost; @@ -194,10 +196,19 @@ rec { ); # Change the result of the function call by applying g to it overrideResult = g: makeOverridable (mirrorArgs (args: g (f args))) origArgs; + newOverriderNames = + filter (n: n != "override" && n != "overrideDerivation" && result ? ${n}) ( + subtractLists (result.__overriders or [ ]) [ "overrideAttrs" ] ++ result.__overriders or [ ] + ) + ++ [ + "override" + "overrideDerivation" + ]; in if isAttrs result then result // { + __overriders = newOverriderNames; override = overrideArgs; overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv); ${if result ? overrideAttrs then "overrideAttrs" else null} = @@ -213,10 +224,16 @@ rec { # design/tech debt issue: https://github.com/NixOS/nixpkgs/issues/273815 fdrv: overrideResult (x: x.overrideAttrs fdrv); } + // optionalAttrs (result ? __overriders) ( + genAttrs (filter ( + x: x != "override" && x != "overrideAttrs" && x != "overrideDerivation" && result ? ${x} + ) result.__overriders) (name: fdrv: overrideResult (x: x.${name} fdrv)) + ) else if isFunction result then # Transform the result into a functor while propagating its arguments setFunctionArgs result (functionArgs result) // { + __overriders = newOverriderNames; override = overrideArgs; } else From 4bd7f344aa3b82538e181e3f6ebcd2a653b67737 Mon Sep 17 00:00:00 2001 From: Yueh-Shun Li Date: Fri, 24 Oct 2025 02:42:23 +0800 Subject: [PATCH 2/3] lib.customisation: makeScope, makeScopeWithSplicing': provide __overriders --- lib/customisation.nix | 2 ++ lib/tests/misc.nix | 67 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/lib/customisation.nix b/lib/customisation.nix index 02a2a956f41c3..d63a219e1ae9e 100644 --- a/lib/customisation.nix +++ b/lib/customisation.nix @@ -656,6 +656,7 @@ rec { newScope = scope: newScope (self // scope); overrideScope = g: makeScope newScope (extends g f); packages = f; + __overriders = [ "overrideScope" ]; }; in self; @@ -774,6 +775,7 @@ rec { f = extends g f; }); packages = f; + __overriders = [ "overrideScope" ]; }; in self; diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index da09797567209..d3b88ce3d8c74 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -87,6 +87,7 @@ let meta mod nameValuePair + optionalAttrs optionalDrvAttr optionAttrSetToDocList overrideExisting @@ -4810,16 +4811,19 @@ runTests { directory = ./packages-from-directory/scope; }); expected = lib.recurseIntoAttrs { + __overriders = [ "overrideScope" ]; a = "a"; b = "b"; # Note: Other files/directories in `./test-data/c/` are ignored and can be # used by `package.nix`. c = "c"; my-namespace = lib.recurseIntoAttrs { + __overriders = [ "overrideScope" ]; d = "d"; e = "e"; f = "f"; my-sub-namespace = lib.recurseIntoAttrs { + __overriders = [ "overrideScope" ]; g = "g"; h = "h"; }; @@ -4876,6 +4880,69 @@ runTests { expected = { foo = "foo-value-custom"; bar = "bar-value-custom"; + + # Test if `makeOverridable` correctly handles `result.ovrerrideScope`, + # so that `makeScope`-constructed, `callPackageWith`-called scope + # won't lose `.override` after `.overrideScope` overriding. + testMakeOverridableForCallPackageAndScope = + let + scope-orig = callPackageWith (lib // { a = 3; }) ( + { + callPackagesWith, + makeScope, + a, + }: + makeScope callPackagesWith (final: { + inherit a; + b = 5; + c = final.a * final.b; + }) + ) { }; + scope-os = scope-orig.overrideScope ( + final: previous: { + b = 7; + } + ); + scope-os-ov = scope-os.override { a = 11; }; + in + { + expr = { + scope-orig-a = scope-orig.a; + scope-orig-b = scope-orig.b; + scope-orig-c = scope-orig.c; + scope-orig-has-override = scope-orig ? override; + scope-orig-has-overrideScope = scope-orig ? overrideScope; + } + // optionalAttrs (scope-orig ? overrideScope) { + scope-os-a = scope-os.a; + scope-os-b = scope-os.b; + scope-os-c = scope-os.c; + scope-os-has-override = scope-os ? override; + scope-os-has-overrideScope = scope-os ? overrideScope; + } + // optionalAttrs (scope-os ? override) { + scope-os-ov-a = scope-os-ov.a; + scope-os-ov-b = scope-os-ov.b; + scope-os-ov-c = scope-os-ov.c; + scope-os-ov-has-override = scope-os-ov ? override; + scope-os-ov-has-overrideScope = scope-os-ov ? overrideScope; + }; + expected = rec { + scope-orig-a = 3; + scope-orig-b = 5; + scope-orig-c = scope-orig-a * scope-orig-b; + scope-orig-has-override = true; + scope-orig-has-overrideScope = true; + scope-os-a = scope-orig-a; + scope-os-b = 7; + scope-os-c = scope-os-a * scope-os-b; + scope-os-has-override = true; + scope-os-has-overrideScope = true; + scope-os-ov-a = 11; + scope-os-ov-b = scope-os-b; + scope-os-ov-c = scope-os-ov-a * scope-os-ov-b; + scope-os-ov-has-override = true; + scope-os-ov-has-overrideScope = true; }; }; From cbdd103ee958dbdbdca8634ca8080a020c1a419c Mon Sep 17 00:00:00 2001 From: Yueh-Shun Li Date: Fri, 24 Oct 2025 02:50:54 +0800 Subject: [PATCH 3/3] lib.makeExtensibleWithCustomName: provide __overriders --- lib/fixed-points.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/fixed-points.nix b/lib/fixed-points.nix index c80a7f72eba83..c3082a0aee980 100644 --- a/lib/fixed-points.nix +++ b/lib/fixed-points.nix @@ -454,6 +454,7 @@ rec { (rattrs self) // { ${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs); + __overriders = [ extenderName ]; } );