From 4752577dd6177044913018acdf2bd456b4e08837 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Tue, 15 Apr 2025 12:26:03 +0200 Subject: [PATCH 1/6] lib.modules: Add _prefix module argument --- lib/modules.nix | 1 + lib/tests/modules.sh | 3 +++ lib/tests/modules/prefix-module-argument.nix | 17 +++++++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 lib/tests/modules/prefix-module-argument.nix diff --git a/lib/modules.nix b/lib/modules.nix index 290b9ce0b698..ad71209a62a3 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -258,6 +258,7 @@ let specialArgs ; _class = class; + _prefix = prefix; } // specialArgs ); diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index d0f25c283dcb..d7006d9c58fc 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -352,6 +352,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 diff --git a/lib/tests/modules/prefix-module-argument.nix b/lib/tests/modules/prefix-module-argument.nix new file mode 100644 index 000000000000..2cb854341a22 --- /dev/null +++ b/lib/tests/modules/prefix-module-argument.nix @@ -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; + }; + }; +} From ce0c6e269d6c0a40c63e1f8b7f40ec1aac0e7ffd Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Tue, 15 Apr 2025 12:28:37 +0200 Subject: [PATCH 2/6] lib.modules: Typos --- lib/modules.nix | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/modules.nix b/lib/modules.nix index ad71209a62a3..89c12bcf1a77 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -2024,12 +2024,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. + 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. '' ] @@ -2058,7 +2059,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 From 38bb05d169a51fc7c7187867440d2968212d1267 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Tue, 15 Apr 2025 12:39:35 +0200 Subject: [PATCH 3/6] lib.modules: Add prefix to imports type check error --- lib/modules.nix | 7 ++++++- lib/tests/modules.sh | 1 + lib/tests/modules/import-error-submodule.nix | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 lib/tests/modules/import-error-submodule.nix diff --git a/lib/modules.nix b/lib/modules.nix index 89c12bcf1a77..73cc9fc94ca4 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -389,6 +389,7 @@ let value = m; _type = m._type; expectedClass = class; + prefix = args._prefix; } ) else if isList m then @@ -1977,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. */ @@ -2029,7 +2034,7 @@ let paragraphs ( [ '' - Expected a module, but found a value of type ${warn (escapeNixString _type)}${into_fallback_file_maybe fallbackFile}. + 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. '' diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index d7006d9c58fc..929543fd827f 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -606,6 +606,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 diff --git a/lib/tests/modules/import-error-submodule.nix b/lib/tests/modules/import-error-submodule.nix new file mode 100644 index 000000000000..d2237c58bb5a --- /dev/null +++ b/lib/tests/modules/import-error-submodule.nix @@ -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 + ]; + }; +} From 1de329f5e181b4e46607934ef323f4931803e42b Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Tue, 15 Apr 2025 13:20:40 +0200 Subject: [PATCH 4/6] doc: Module arguments --- doc/module-system/module-system.chapter.md | 45 ++++++++++++++++++++++ doc/redirects.json | 18 +++++++++ 2 files changed, 63 insertions(+) diff --git a/doc/module-system/module-system.chapter.md b/doc/module-system/module-system.chapter.md index 0c91012eebb4..eaeda870def6 100644 --- a/doc/module-system/module-system.chapter.md +++ b/doc/module-system/module-system.chapter.md @@ -115,3 +115,48 @@ 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`] which were 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} + +A reference to the Nixpkgs library. + +### `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} + +All evaluated option declarations. + +### `_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} + +The location under which the module is evaluated. This is used to improve error reporting and find the implicit `name` module argument in submodules. + +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). +Any dependencies on `_prefix` should be replaced with explicit options, whose default definitions can be provided by the module that imports them. + +[`evalModules`]: #module-system-lib-evalModules +[`specialArgs`]: #module-system-lib-evalModules-param-specialArgs diff --git a/doc/redirects.json b/doc/redirects.json index 2a8069a490bb..714e4a691753 100644 --- a/doc/redirects.json +++ b/doc/redirects.json @@ -4363,5 +4363,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" ] } From 5e6504c0dfc3663665ce05bb52489150ab014fca Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Fri, 9 May 2025 18:26:10 +0200 Subject: [PATCH 5/6] doc/module-system: Apply suggestions from code review Co-authored-by: Valentin Gagarin --- doc/module-system/module-system.chapter.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/module-system/module-system.chapter.md b/doc/module-system/module-system.chapter.md index eaeda870def6..6ea9f4a4116f 100644 --- a/doc/module-system/module-system.chapter.md +++ b/doc/module-system/module-system.chapter.md @@ -127,7 +127,7 @@ They originate from these sources: - `options`, - `_class`, - `_prefix`, -2. Attributes from the [`specialArgs`] which were passed to [`evalModules`] or `submoduleWith`. These are application-specific. +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 @@ -152,11 +152,13 @@ The [expected class](#module-system-lib-evalModules-param-class) of the loaded m ### `_prefix` {#module-system-module-argument-_prefix} -The location under which the module is evaluated. This is used to improve error reporting and find the implicit `name` module argument in submodules. +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). -Any dependencies on `_prefix` should be replaced with explicit options, whose default definitions can be provided by the module that imports them. +Instead of depending on `_prefix` use explicit options, whose default definitions can be provided by the module that imports them. [`evalModules`]: #module-system-lib-evalModules [`specialArgs`]: #module-system-lib-evalModules-param-specialArgs From 736327d6ca401e4bbcc8272d9604ec0a4cfe2630 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Fri, 9 May 2025 18:39:42 +0200 Subject: [PATCH 6/6] doc/module-system: Adjust markdown syntax --- doc/module-system/module-system.chapter.md | 48 ++++++++++------------ 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/doc/module-system/module-system.chapter.md b/doc/module-system/module-system.chapter.md index 6ea9f4a4116f..8c27aea15ffc 100644 --- a/doc/module-system/module-system.chapter.md +++ b/doc/module-system/module-system.chapter.md @@ -122,43 +122,39 @@ Module arguments are the attribute values passed to modules when they are evalua They originate from these sources: 1. Built-in arguments - - `lib`, - - `config`, - - `options`, - - `_class`, - - `_prefix`, + - `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} +[`lib`]{#module-system-module-argument-lib} [🔗](#module-system-module-argument-lib) +: A reference to the Nixpkgs library. -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`. -### `config` {#module-system-module-argument-config} +[`options`]{#module-system-module-argument-options} [🔗](#module-system-module-argument-options) +: All evaluated option declarations. -All option values. -Unlike the `evalModules` [`config` return attribute](#module-system-lib-evalModules-return-value-config), this includes `_module`. +[`_class`]{#module-system-module-argument-_class} [🔗](#module-system-module-argument-_class) +: The [expected class](#module-system-lib-evalModules-param-class) of the loaded modules. -### `options` {#module-system-module-argument-options} +[`_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. -All evaluated option declarations. - -### `_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} - -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. + 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. + [`evalModules`]: #module-system-lib-evalModules [`specialArgs`]: #module-system-lib-evalModules-param-specialArgs