+4
-1
doc/doc-support/default.nix
+4
-1
doc/doc-support/default.nix
···
+4
doc/manual.xml
+4
doc/manual.xml
···
+105
doc/module-system/module-system.chapter.md
+105
doc/module-system/module-system.chapter.md
···+This chapter is new and not complete yet. For a gentle introduction to the module system, in the context of NixOS, see [Writing NixOS Modules](https://nixos.org/manual/nixos/unstable/index.html#sec-writing-modules) in the NixOS manual.+Evaluate a set of modules. This function is typically only used once per application (e.g. once in NixOS, once in Home Manager, ...).+This is in contrast to `config._module.args`, which is only available after all `imports` have been resolved.+If the `class` attribute is set and non-`null`, the module system will reject `imports` with a different `_class` declaration.+The `class` value should be a string in lower [camel case](https://en.wikipedia.org/wiki/Camel_case).+If applicable, the `class` should match the "prefix" of the attributes used in (experimental) [flakes](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html#description). Some examples are:+- `nixosTest`: modules that constitute a [NixOS VM test](https://nixos.org/manual/nixos/stable/index.html#sec-nixos-tests)+A list of strings representing the location at or below which all options are evaluated. This is used by `types.submodule` to improve error reporting and find the implicit `name` module argument.+A module system type. This type is an instance of `types.submoduleWith` containing the current [`modules`](#module-system-lib-evalModules-param-modules).+The option definitions that are typed with this type will extend the current set of modules, like [`extendModules`](#module-system-lib-evalModules-return-value-extendModules).+However, the value returned from the type is just the [`config`](#module-system-lib-evalModules-return-value-config), like any submodule.+If you're familiar with prototype inheritance, you can think of this `evalModules` invocation as the prototype, and usages of this type as the instances.+This type is also available to the [`modules`](#module-system-lib-evalModules-param-modules) as the module argument `moduleType`.+<!-- TODO: document the module arguments. Using moduleType is like saying: suppose this configuration was extended. -->+A function similar to `evalModules` but building on top of the already passed [`modules`](#module-system-lib-evalModules-param-modules). Its arguments, `modules` and `specialArgs` are added to the existing values.+If you're familiar with prototype inheritance, you can think of the current, actual `evalModules` invocation as the prototype, and the return value of `extendModules` as the instance.+`extendModules` returns a configuration that shares very little with the original `evalModules` invocation, because the module arguments may be different.+So if you have a configuration that has been (or will be) largely evaluated, almost none of the computation is shared with the configuration returned by `extendModules`.+The real work of module evaluation happens while computing the values in `config` and `options`, so multiple invocations of `extendModules` have a particularly small cost, as long as only the final `config` and `options` are evaluated.+If you do reference multiple `config` (or `options`) from before and after `extendModules`, evaluation performance is the same as with multiple `evalModules` invocations, because the new modules' ability to override existing configuration fundamentally requires constructing a new `config` and `options` fixpoint.+<!-- TODO: when markdown migration is complete, make _module docs visible again and reference _module docs. Maybe move those docs into this chapter? -->
+113
-47
lib/modules.nix
+113
-47
lib/modules.nix
············-# collectModules :: (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]+# collectModules :: (class: String) -> (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]+"Could not load a value as a module, because it is of type ${lib.strings.escapeNixString m._type}"++ lib.optionalString (m._type == "configuration") " If you do intend to import this configuration, please only import the modules that make up the configuration. You may have to create a `let` binding, file or attribute to give yourself access to the relevant modules.\nWhile loading a configuration into the module system is a very sensible idea, it can not be done cleanly in practice."+# Extended explanation: That's because a finalized configuration is more than just a set of modules. For instance, it has its own `specialArgs` that, by the nature of `specialArgs` can't be loaded through `imports` or the the `modules` argument. So instead, we have to ask you to extract the relevant modules and use those instead. This way, we keep the module system comparatively simple, and hopefully avoid a bad surprise down the line.throw "Module imports can't be nested lists. Perhaps you meant to remove one level of lists? Definitions: ${showDefs defs}"else unifyModuleSyntax (toString m) (toString m) (applyModuleArgsIfFunction (toString m) (import m) args);······-let badAttrs = removeAttrs m ["_file" "key" "disabledModules" "imports" "options" "config" "meta" "freeformType"]; in+let badAttrs = removeAttrs m ["_class" "_file" "key" "disabledModules" "imports" "options" "config" "meta" "freeformType"]; inthrow "Module `${key}' has an unsupported attribute `${head (attrNames badAttrs)}'. This is caused by introducing a top-level `config' or `options' attribute. Add configuration attributes immediately on the top level instead, or move all of them (namely: ${toString (attrNames badAttrs)}) into the explicit `config' attribute."···-config = addFreeformType (removeAttrs m ["_file" "key" "disabledModules" "require" "imports" "freeformType"]);+config = addFreeformType (removeAttrs m ["_class" "_file" "key" "disabledModules" "require" "imports" "freeformType"]);······+(k: lib.warn "External use of `lib.modules.${k}` is deprecated. If your use case isn't covered by non-deprecated functions, we'd like to know more and perhaps support your use case well, instead of providing access to these low level functions. In this case please open an issue in https://github.com/nixos/nixpkgs/issues/.")
+21
lib/tests/modules.sh
+21
lib/tests/modules.sh
···checkConfigOutput '^"24"$' config.value ./declare-coerced-value.nix ./define-value-string.nixcheckConfigError 'A definition for option .* is not.*string or signed integer convertible to it.*. Definition values:\n\s*- In .*: \[ \]' config.value ./declare-coerced-value.nix ./define-value-list.nix···+checkConfigOutput '^true$' options._module.args.value.result ./freeform-attrsOf.nix ./define-freeform-keywords-shorthand.nix···+checkConfigError 'The module .*/module-class-is-darwin.nix was imported into nixos instead of darwin.' config.fail.config ./class-check.nix+checkConfigError 'The module foo.nix#darwinModules.default was imported into nixos instead of darwin.' config.fail-anon.config ./class-check.nix+checkConfigError 'The module .*/module-class-is-darwin.nix was imported into nixos instead of darwin.' config.sub.nixosFail.config ./class-check.nix+checkConfigError 'error: A submoduleWith option is declared multiple times with conflicting class values "darwin" and "nixos".' config.sub.mergeFail.config ./class-check.nix+checkConfigError 'Could not load a value as a module, because it is of type "flake", in file .*/module-imports-_type-check.nix' config.ok.config ./module-imports-_type-check.nix+checkConfigOutput '^true$' "$@" config.enable ./declare-enable.nix ./define-enable-with-top-level-mkIf.nix+checkConfigError 'Could not load a value as a module, because it is of type "configuration", in file .*/import-configuration.nix.*please only import the modules that make up the configuration.*' config ./import-configuration.nix
+76
lib/tests/modules/class-check.nix
+76
lib/tests/modules/class-check.nix
···
+5
lib/tests/modules/define-enable-with-top-level-mkIf.nix
+5
lib/tests/modules/define-enable-with-top-level-mkIf.nix
+15
lib/tests/modules/define-freeform-keywords-shorthand.nix
+15
lib/tests/modules/define-freeform-keywords-shorthand.nix
···
+12
lib/tests/modules/import-configuration.nix
+12
lib/tests/modules/import-configuration.nix
···
+4
lib/tests/modules/module-class-is-darwin.nix
+4
lib/tests/modules/module-class-is-darwin.nix
+4
lib/tests/modules/module-class-is-nixos.nix
+4
lib/tests/modules/module-class-is-nixos.nix
+3
lib/tests/modules/module-imports-_type-check.nix
+3
lib/tests/modules/module-imports-_type-check.nix
+8
-2
lib/types.nix
+8
-2
lib/types.nix
·········+else throw "A submoduleWith option is declared multiple times with conflicting class values \"${toString lhs.class}\" and \"${toString rhs.class}\".";
+1
nixos/lib/eval-cacheable-options.nix
+1
nixos/lib/eval-cacheable-options.nix
+1
nixos/lib/eval-config-minimal.nix
+1
nixos/lib/eval-config-minimal.nix
+4
-1
nixos/lib/testing/default.nix
+4
-1
nixos/lib/testing/default.nix
···runTest = module: (evalTest ({ config, ... }: { imports = [ module ]; result = config.test; })).config.result;
+1
nixos/modules/misc/documentation.nix
+1
nixos/modules/misc/documentation.nix