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