diff --git a/lib/introspection/default.nix b/lib/introspection/default.nix index 3da43427b..cf74c1bd5 100644 --- a/lib/introspection/default.nix +++ b/lib/introspection/default.nix @@ -164,7 +164,20 @@ let else getPrios { options = opt; } ) filteredOptions; + + getPriosLegacy = import ./getPriosLegacy.nix { inherit lib; }; + + wrap = + { + options, + }: + # Test _module.check for valueMeta + # This option should always exist if options comes from a module evaluation + if options._module.check ? valueMeta then + getPrios { inherit options; } + else + getPriosLegacy { inherit options; }; in { - inherit getPrios; + getPrios = wrap; } diff --git a/lib/introspection/getPriosLegacy.nix b/lib/introspection/getPriosLegacy.nix new file mode 100644 index 000000000..e7aa7b411 --- /dev/null +++ b/lib/introspection/getPriosLegacy.nix @@ -0,0 +1,98 @@ +{ + lib ? import , +}: +let + filterOptions = lib.filterAttrs ( + name: _: + !builtins.elem name [ + "_module" + "_freeformOptions" + ] + ); + + # Use for nixpkgs < 25.11 + getPriosLegacy = + { + options, + }: + let + filteredOptions = filterOptions options; + in + lib.mapAttrs ( + _: opt: + let + prio = { + __prio = opt.highestPrio; + }; + filteredSubOptions = filterOptions (opt.type.getSubOptions opt.loc); + + zipDefs = builtins.zipAttrsWith (_: vs: vs); + + prioPerValue = + { type, defs }: + lib.mapAttrs ( + attrName: prioSet: + let + # Evaluate the submodule + # Remove once: https://github.com/NixOS/nixpkgs/pull/391544 lands + # This is currently a workaround to get the submodule options + # It also has a certain loss of information, on nested attrsOf, which is rare, but not ideal. + options = filteredSubOptions; + modules = ( + [ + { + inherit options; + _file = ""; + } + ] + ++ map (config: { inherit config; }) defs.${attrName} + ); + submoduleEval = lib.evalModules { + inherit modules; + }; + in + (lib.optionalAttrs (prioSet ? highestPrio) { + __prio = prioSet.highestPrio; + }) + // ( + if type.nestedTypes.elemType.name == "submodule" then + getPriosLegacy { options = submoduleEval.options; } + else + # Nested attrsOf + (lib.optionalAttrs + (type.nestedTypes.elemType.name == "attrsOf" || type.nestedTypes.elemType.name == "lazyAttrsOf") + ( + prioPerValue { + type = type.nestedTypes.elemType; + defs = zipDefs defs.${attrName}; + } prioSet.value + ) + ) + ) + ); + + submodulePrios = + let + modules = (opt.definitions ++ opt.type.getSubModules); + submoduleEval = lib.evalModules { + inherit modules; + }; + in + getPriosLegacy { options = filterOptions submoduleEval.options; }; + + in + if opt ? type && opt.type.name == "submodule" then + (prio) // submodulePrios + else if opt ? type && (opt.type.name == "attrsOf" || opt.type.name == "lazyAttrsOf") then + prio + // (prioPerValue { + type = opt.type; + defs = zipDefs opt.definitions; + } (lib.modules.mergeAttrDefinitionsWithPrio opt)) + else if opt ? type && opt._type == "option" then + prio + else + getPriosLegacy { options = opt; } + ) filteredOptions; +in +getPriosLegacy