From 7ae278da36bbfd210a23fb387f7dfdb1646384ef Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Fri, 9 Jan 2026 20:14:23 +0100 Subject: [PATCH] meta-types.nix: Refactor --- pkgs/stdenv/generic/check-meta.nix | 36 +++---------------- pkgs/stdenv/generic/meta-types.nix | 55 +++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 32 deletions(-) diff --git a/pkgs/stdenv/generic/check-meta.nix b/pkgs/stdenv/generic/check-meta.nix index cfc08ba9847f..95de2a144df9 100644 --- a/pkgs/stdenv/generic/check-meta.nix +++ b/pkgs/stdenv/generic/check-meta.nix @@ -317,7 +317,7 @@ let ${concatStrings (map (output: " - ${output}\n") missingOutputs)} ''; - metaTypes = + metaType = let types = import ./meta-types.nix { inherit lib; }; inherit (types) @@ -329,13 +329,14 @@ let any listOf bool + record ; platforms = listOf (union [ str (attrsOf any) ]); # see lib.meta.platformMatch in - { + record { # These keys are documented description = str; mainProgram = str; @@ -404,34 +405,7 @@ let identifiers = attrs; }; - # Map attrs directly to the verify function for performance - metaTypes' = mapAttrs (_: t: t.verify) metaTypes; - - checkMetaAttr = - k: v: - if metaTypes ? ${k} then - if metaTypes'.${k} v then - [ ] - else - [ - "key 'meta.${k}' has invalid value; expected ${metaTypes.${k}.name}, got\n ${ - toPretty { indent = " "; } v - }" - ] - else - [ - "key 'meta.${k}' is unrecognized; expected one of: \n [${ - concatMapStringsSep ", " (x: "'${x}'") (attrNames metaTypes) - }]" - ]; - - checkMeta = meta: concatMap (attr: checkMetaAttr attr meta.${attr}) (attrNames meta); - - metaInvalid = - if config.checkMeta then - meta: !all (attr: metaTypes ? ${attr} && metaTypes'.${attr} meta.${attr}) (attrNames meta) - else - meta: false; + metaInvalid = if config.checkMeta then meta: !metaType.verify meta else meta: false; checkOutputsToInstall = if config.checkMeta then @@ -459,7 +433,7 @@ let { reason = "unknown-meta"; errormsg = "has an invalid meta attrset:${ - concatMapStrings (x: "\n - " + x) (checkMeta attrs.meta) + concatMapStrings (x: "\n - " + x) (metaType.errors "${getName attrs}.meta" attrs.meta) }\n"; remediation = ""; } diff --git a/pkgs/stdenv/generic/meta-types.nix b/pkgs/stdenv/generic/meta-types.nix index a51ae2b12711..1c53e6b7bf9d 100644 --- a/pkgs/stdenv/generic/meta-types.nix +++ b/pkgs/stdenv/generic/meta-types.nix @@ -12,16 +12,40 @@ let isList all any + attrNames attrValues + concatMap isFunction isBool concatStringsSep + concatMapStringsSep isFloat + elem + mapAttrs ; isTypeDef = t: isAttrs t && t ? name && isString t.name && t ? verify && isFunction t.verify; - in lib.fix (self: { + + /* + `errors type "" value` gives a list of string error messages, + each prefixed with ": ", for why `value` is not of type `type` + + Only use this if `type.verify value` is false + + Types can override this by specifying their own `type.errors = ctx: value:` attribute + + This is intentionally not tied into `type.verify`, + in order to keep the successful path as fast as possible with minimal allocations + */ + errors = + t: + t.errors or (ctx: v: [ + "${ctx}: Invalid value; expected ${t.name}, got\n ${ + lib.generators.toPretty { indent = " "; } v + }" + ]); + string = { name = "string"; verify = isString; @@ -95,4 +119,33 @@ lib.fix (self: { name = "union<${concatStringsSep "," (map (t: t.name) types)}>"; verify = v: any (func: func v) funcs; }; + + record = + fields: + assert isAttrs fields && all isTypeDef (attrValues fields); + let + # Map attrs directly to the verify function for performance + fieldVerifiers = mapAttrs (_: t: t.verify) fields; + in + { + name = "record"; + verify = v: isAttrs v && all (k: fieldVerifiers ? ${k} && fieldVerifiers.${k} v.${k}) (attrNames v); + errors = + ctx: v: + if !isAttrs v then + self.errors self.attrs ctx v + else + concatMap ( + k: + if fieldVerifiers ? ${k} then + lib.optionals (fieldVerifiers.${k} v.${k}) (self.errors fields.${k} (ctx + ".${k}") v.${k}) + else + [ + "${ctx}: key '${k}' is unrecognized; expected one of: \n [${ + concatMapStringsSep ", " (x: "'${x}'") (attrNames fields) + }]" + ] + ) (attrNames v); + }; + })