modules: Add _prefix
module argument, improve error, add docs (#398839)
This commit is contained in:
commit
1849ee507e
@ -115,3 +115,46 @@ A nominal type marker, always `"configuration"`.
|
||||
#### `class` {#module-system-lib-evalModules-return-value-_configurationClass}
|
||||
|
||||
The [`class` argument](#module-system-lib-evalModules-param-class).
|
||||
|
||||
## Module arguments {#module-system-module-arguments}
|
||||
|
||||
Module arguments are the attribute values passed to modules when they are evaluated.
|
||||
|
||||
They originate from these sources:
|
||||
1. Built-in arguments
|
||||
- `lib`,
|
||||
- `config`,
|
||||
- `options`,
|
||||
- `_class`,
|
||||
- `_prefix`,
|
||||
2. Attributes from the [`specialArgs`] argument passed to [`evalModules`] or `submoduleWith`. These are application-specific.
|
||||
3. Attributes from the `_module.args` option value. These are application-specific and can be provided by any module.
|
||||
|
||||
The prior two categories are available while evaluating the `imports`, whereas
|
||||
the last category is only available after the `imports` have been resolved.
|
||||
|
||||
[`lib`]{#module-system-module-argument-lib} [🔗](#module-system-module-argument-lib)
|
||||
: A reference to the Nixpkgs library.
|
||||
|
||||
[`config`]{#module-system-module-argument-config} [🔗](#module-system-module-argument-config)
|
||||
: All option values.
|
||||
Unlike the `evalModules` [`config` return attribute](#module-system-lib-evalModules-return-value-config), this includes `_module`.
|
||||
|
||||
[`options`]{#module-system-module-argument-options} [🔗](#module-system-module-argument-options)
|
||||
: All evaluated option declarations.
|
||||
|
||||
[`_class`]{#module-system-module-argument-_class} [🔗](#module-system-module-argument-_class)
|
||||
: The [expected class](#module-system-lib-evalModules-param-class) of the loaded modules.
|
||||
|
||||
[`_prefix`]{#module-system-module-argument-_prefix} [🔗](#module-system-module-argument-_prefix)
|
||||
: The location under which the module is evaluated.
|
||||
This is used to improve error reporting and to find the implicit `name` module argument in submodules.
|
||||
It is exposed as a module argument due to how the module system is implemented, which cannot be avoided without breaking compatibility.
|
||||
|
||||
It is a good practice not to rely on `_prefix`. A module should not make assumptions about its location in the configuration tree.
|
||||
For example, the root of a NixOS configuration may have a non-empty prefix, for example when it is a specialisation, or when it is part of a larger, multi-host configuration such as a [NixOS test](https://nixos.org/manual/nixos/unstable/#sec-nixos-tests).
|
||||
Instead of depending on `_prefix` use explicit options, whose default definitions can be provided by the module that imports them.
|
||||
|
||||
<!-- markdown link aliases -->
|
||||
[`evalModules`]: #module-system-lib-evalModules
|
||||
[`specialArgs`]: #module-system-lib-evalModules-param-specialArgs
|
||||
|
@ -4515,5 +4515,23 @@
|
||||
],
|
||||
"sec-interop.cylonedx-fod": [
|
||||
"index.html#sec-interop.cylonedx-fod"
|
||||
],
|
||||
"module-system-module-argument-_prefix": [
|
||||
"index.html#module-system-module-argument-_prefix"
|
||||
],
|
||||
"module-system-module-argument-lib": [
|
||||
"index.html#module-system-module-argument-lib"
|
||||
],
|
||||
"module-system-module-argument-config": [
|
||||
"index.html#module-system-module-argument-config"
|
||||
],
|
||||
"module-system-module-arguments": [
|
||||
"index.html#module-system-module-arguments"
|
||||
],
|
||||
"module-system-module-argument-_class": [
|
||||
"index.html#module-system-module-argument-_class"
|
||||
],
|
||||
"module-system-module-argument-options": [
|
||||
"index.html#module-system-module-argument-options"
|
||||
]
|
||||
}
|
||||
|
@ -258,6 +258,7 @@ let
|
||||
specialArgs
|
||||
;
|
||||
_class = class;
|
||||
_prefix = prefix;
|
||||
}
|
||||
// specialArgs
|
||||
);
|
||||
@ -388,6 +389,7 @@ let
|
||||
value = m;
|
||||
_type = m._type;
|
||||
expectedClass = class;
|
||||
prefix = args._prefix;
|
||||
}
|
||||
)
|
||||
else if isList m then
|
||||
@ -1976,6 +1978,10 @@ let
|
||||
file != null && file != unknownModule
|
||||
) ", while trying to load a module into ${toString file}";
|
||||
|
||||
into_prefix_maybe =
|
||||
prefix:
|
||||
optionalString (prefix != [ ]) ", while trying to load a module into ${code (showOption prefix)}";
|
||||
|
||||
/**
|
||||
Format text with one line break between each list item.
|
||||
*/
|
||||
@ -2023,12 +2029,13 @@ let
|
||||
value,
|
||||
_type,
|
||||
expectedClass ? null,
|
||||
prefix,
|
||||
}:
|
||||
paragraphs (
|
||||
[
|
||||
''
|
||||
Expected a module, but found a value of type ${warn (escapeNixString _type)}${into_fallback_file_maybe fallbackFile}.
|
||||
A module is typically loaded by adding it the ${code "imports = [ ... ];"} attribute of an existing module, or in the ${code "modules = [ ... ];"} argument of various functions.
|
||||
Expected a module, but found a value of type ${warn (escapeNixString _type)}${into_fallback_file_maybe fallbackFile}${into_prefix_maybe prefix}.
|
||||
A module is typically loaded by adding it to the ${code "imports = [ ... ];"} attribute of an existing module, or in the ${code "modules = [ ... ];"} argument of various functions.
|
||||
Please make sure that each of the list items is a module, and not a different kind of value.
|
||||
''
|
||||
]
|
||||
@ -2057,7 +2064,7 @@ let
|
||||
'')
|
||||
]
|
||||
++ optionalMatch {
|
||||
# We'll no more than 5 custom suggestions here.
|
||||
# We'll add no more than 5 custom suggestions here.
|
||||
# Please switch to `.modules.${class}` in your Module System application.
|
||||
"nixos" = trim ''
|
||||
or
|
||||
|
@ -364,6 +364,9 @@ checkConfigOutput '^"submodule"$' options.submodule.type.description ./declare-s
|
||||
## Paths should be allowed as values and work as expected
|
||||
checkConfigOutput '^true$' config.submodule.enable ./declare-submoduleWith-path.nix
|
||||
|
||||
## _prefix module argument is available at import time and contains the prefix
|
||||
checkConfigOutput '^true$' config.foo.ok ./prefix-module-argument.nix
|
||||
|
||||
## deferredModule
|
||||
# default module is merged into nodes.foo
|
||||
checkConfigOutput '"beta"' config.nodes.foo.settingsDict.c ./deferred-module.nix
|
||||
@ -615,6 +618,7 @@ checkConfigError 'Expected a module, but found a value of type .*"flake".*, whil
|
||||
checkConfigOutput '^true$' config.enable ./declare-enable.nix ./define-enable-with-top-level-mkIf.nix
|
||||
checkConfigError 'Expected a module, but found a value of type .*"configuration".*, while trying to load a module into .*/import-configuration.nix.' config ./import-configuration.nix
|
||||
checkConfigError 'please only import the modules that make up the configuration' config ./import-configuration.nix
|
||||
checkConfigError 'Expected a module, but found a value of type "configuration", while trying to load a module into .*/import-error-submodule.nix, while trying to load a module into .*foo.*\.' config.foo ./import-error-submodule.nix
|
||||
|
||||
# doRename works when `warnings` does not exist.
|
||||
checkConfigOutput '^1234$' config.c.d.e ./doRename-basic.nix
|
||||
|
18
lib/tests/modules/import-error-submodule.nix
Normal file
18
lib/tests/modules/import-error-submodule.nix
Normal file
@ -0,0 +1,18 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
myconf = lib.evalModules { modules = [ { } ]; };
|
||||
in
|
||||
{
|
||||
options.foo = lib.mkOption {
|
||||
type = lib.types.submodule { };
|
||||
default = { };
|
||||
};
|
||||
config.foo =
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
# error, like `import-configuration.nix`, but in a submodule this time
|
||||
myconf
|
||||
];
|
||||
};
|
||||
}
|
17
lib/tests/modules/prefix-module-argument.nix
Normal file
17
lib/tests/modules/prefix-module-argument.nix
Normal file
@ -0,0 +1,17 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
options.foo = lib.mkOption {
|
||||
type = lib.types.submodule { };
|
||||
default = { };
|
||||
};
|
||||
|
||||
config = {
|
||||
foo =
|
||||
{ _prefix, ... }:
|
||||
assert _prefix == [ "foo" ];
|
||||
{
|
||||
options.ok = lib.mkOption { };
|
||||
config.ok = true;
|
||||
};
|
||||
};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user