diff options
author | Linus Heckemann <git@sphalerite.org> | 2021-09-29 11:03:31 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-29 11:03:31 +0200 |
commit | a3df3d05e5db17b26ff886f53a58761a547561cc (patch) | |
tree | 3048af8fedf275f86fe60185936381823faffdd8 | |
parent | 40f34902e623ad3c130bbdb2a65c53610e933307 (diff) | |
parent | 681758d41588c27aaa6f3c3a72184dcc4d0aeba8 (diff) | |
download | nixpkgs-a3df3d05e5db17b26ff886f53a58761a547561cc.tar nixpkgs-a3df3d05e5db17b26ff886f53a58761a547561cc.tar.gz nixpkgs-a3df3d05e5db17b26ff886f53a58761a547561cc.tar.bz2 nixpkgs-a3df3d05e5db17b26ff886f53a58761a547561cc.tar.lz nixpkgs-a3df3d05e5db17b26ff886f53a58761a547561cc.tar.xz nixpkgs-a3df3d05e5db17b26ff886f53a58761a547561cc.tar.zst nixpkgs-a3df3d05e5db17b26ff886f53a58761a547561cc.zip |
Merge pull request #131205 from Ma27/showdefs-overflow
lib/modules: improve errors for `options`/`config`-mixups
-rw-r--r-- | lib/generators.nix | 27 | ||||
-rw-r--r-- | lib/modules.nix | 25 | ||||
-rw-r--r-- | lib/options.nix | 4 | ||||
-rw-r--r-- | lib/tests/misc.nix | 19 |
4 files changed, 66 insertions, 9 deletions
diff --git a/lib/generators.nix b/lib/generators.nix index 0cec4d2dd62..79ae9055ce3 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -197,6 +197,30 @@ rec { */ toYAML = {}@args: toJSON args; + withRecursion = + args@{ + /* If this option is not null, the given value will stop evaluating at a certain depth */ + depthLimit + /* If this option is true, an error will be thrown, if a certain given depth is exceeded */ + , throwOnDepthLimit ? true + }: + assert builtins.isInt depthLimit; + let + transform = depth: + if depthLimit != null && depth > depthLimit then + if throwOnDepthLimit + then throw "Exceeded maximum eval-depth limit of ${toString depthLimit} while trying to evaluate with `generators.withRecursion'!" + else const "<unevaluated>" + else id; + mapAny = with builtins; depth: v: + let + evalNext = x: mapAny (depth + 1) (transform (depth + 1) x); + in + if isAttrs v then mapAttrs (const evalNext) v + else if isList v then map evalNext v + else transform (depth + 1) v; + in + mapAny 0; /* Pretty print a value, akin to `builtins.trace`. * Should probably be a builtin as well. @@ -208,7 +232,8 @@ rec { allowPrettyValues ? false, /* If this option is true, the output is indented with newlines for attribute sets and lists */ multiline ? true - }@args: let + }@args: + let go = indent: v: with builtins; let isPath = v: typeOf v == "path"; introSpace = if multiline then "\n${indent} " else " "; diff --git a/lib/modules.nix b/lib/modules.nix index b124ea000a2..46ae3f13631 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -162,13 +162,24 @@ rec { baseMsg = "The option `${showOption (prefix ++ firstDef.prefix)}' does not exist. Definition values:${showDefs [ firstDef ]}"; in if attrNames options == [ "_module" ] - then throw '' - ${baseMsg} - - However there are no options defined in `${showOption prefix}'. Are you sure you've - declared your options properly? This can happen if you e.g. declared your options in `types.submodule' - under `config' rather than `options'. - '' + then + let + optionName = showOption prefix; + in + if optionName == "" + then throw '' + ${baseMsg} + + It seems as if you're trying to declare an option by placing it into `config' rather than `options'! + '' + else + throw '' + ${baseMsg} + + However there are no options defined in `${showOption prefix}'. Are you sure you've + declared your options properly? This can happen if you e.g. declared your options in `types.submodule' + under `config' rather than `options'. + '' else throw baseMsg else null; diff --git a/lib/options.nix b/lib/options.nix index 204c86df9f5..119a67fb7d8 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -247,7 +247,9 @@ rec { showDefs = defs: concatMapStrings (def: let # Pretty print the value for display, if successful - prettyEval = builtins.tryEval (lib.generators.toPretty {} def.value); + prettyEval = builtins.tryEval + (lib.generators.toPretty { } + (lib.generators.withRecursion { depthLimit = 10; throwOnDepthLimit = false; } def.value)); # Split it into its lines lines = filter (v: ! isList v) (builtins.split "\n" prettyEval.value); # Only display the first 5 lines, and indent them for better visibility diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 4b2e5afc1d6..00eeaa2a77d 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -529,6 +529,25 @@ runTests { }; }; + testToPrettyLimit = + let + a.b = 1; + a.c = a; + in { + expr = generators.toPretty { } (generators.withRecursion { throwOnDepthLimit = false; depthLimit = 2; } a); + expected = "{\n b = 1;\n c = {\n b = \"<unevaluated>\";\n c = {\n b = \"<unevaluated>\";\n c = \"<unevaluated>\";\n };\n };\n}"; + }; + + testToPrettyLimitThrow = + let + a.b = 1; + a.c = a; + in { + expr = (builtins.tryEval + (generators.toPretty { } (generators.withRecursion { depthLimit = 2; } a))).success; + expected = false; + }; + testToPrettyMultiline = { expr = mapAttrs (const (generators.toPretty { })) rec { list = [ 3 4 [ false ] ]; |