lib.modules: Improve option-is-prefix error message

Changed files
+39 -3
lib
+21 -3
lib/modules.nix
···
catAttrs
concatLists
concatMap
+
concatStringsSep
elem
filter
findFirst
···
showOption
unknownModule
;
+
+
showDeclPrefix = loc: decl: prefix:
+
" - option(s) with prefix `${showOption (loc ++ [prefix])}' in module `${decl._file}'";
+
showRawDecls = loc: decls:
+
concatStringsSep "\n"
+
(sort (a: b: a < b)
+
(concatMap
+
(decl: map
+
(showDeclPrefix loc decl)
+
(attrNames decl.options)
+
)
+
decls
+
));
+
in
rec {
···
unmatchedDefns = [];
}
else if optionDecls != [] then
-
if (lib.head optionDecls).options.type.name == "submodule"
+
if all (x: x.options.type.name == "submodule") optionDecls
# Raw options can only be merged into submodules. Merging into
# attrsets might be nice, but ambiguous. Suppose we have
# attrset as a `attrsOf submodule`. User declares option
···
# b. option `foo.bar` is available in all `attrset.*`
# c. reject and require "<name>" as a reminder that it behaves like (b).
# d. magically combine (a) and (c).
-
# All options are merely syntax sugar though.
+
# All of the above are merely syntax sugar though.
then
let opt = fixupOptionType loc (mergeOptionDecls loc (map optionTreeToOption decls));
in {
···
else
let
firstNonOption = findFirst (m: !isOption m.options) "" decls;
+
nonOptions = filter (m: !isOption m.options) decls;
in
-
throw "The option `${showOption loc}' in `${(lib.head optionDecls)._file}' is a prefix of options in `${firstNonOption._file}'."
+
throw "The option `${showOption loc}' in module `${(lib.head optionDecls)._file}' would be a parent of the following options, but its type `${(lib.head optionDecls).options.type.description or "<no description>"}' does not support nested options.\n${
+
showRawDecls loc nonOptions
+
}"
else
mergeModules' loc decls defns) declsByName;
+6
lib/tests/modules.sh
···
checkConfigError "The option .multiple. is defined multiple times" config.multiple ./raw.nix
checkConfigOutput "bar" config.priorities ./raw.nix
+
## Option collision
+
checkConfigError \
+
'The option .set. in module .*/declare-set.nix. would be a parent of the following options, but its type .attribute set of signed integers. does not support nested options.\n\s*- option[(]s[)] with prefix .set.enable. in module .*/declare-enable-nested.nix.' \
+
config.set \
+
./declare-set.nix ./declare-enable-nested.nix
+
# Test that types.optionType merges types correctly
checkConfigOutput '^10$' config.theOption.int ./optionTypeMerging.nix
checkConfigOutput '^"hello"$' config.theOption.str ./optionTypeMerging.nix
+12
lib/tests/modules/declare-set.nix
···
+
{ lib, ... }:
+
+
{
+
options.set = lib.mkOption {
+
default = { };
+
example = { a = 1; };
+
type = lib.types.attrsOf lib.types.int;
+
description = ''
+
Some descriptive text
+
'';
+
};
+
}