diff --git a/nixos/doc/manual/development/freeform-modules.section.md b/nixos/doc/manual/development/freeform-modules.section.md new file mode 100644 index 000000000000..10e876b96d59 --- /dev/null +++ b/nixos/doc/manual/development/freeform-modules.section.md @@ -0,0 +1,79 @@ +# Freeform modules {#sec-freeform-modules} + +Freeform modules allow you to define values for option paths that have +not been declared explicitly. This can be used to add attribute-specific +types to what would otherwise have to be `attrsOf` options in order to +accept all attribute names. + +This feature can be enabled by using the attribute `freeformType` to +define a freeform type. By doing this, all assignments without an +associated option will be merged using the freeform type and combined +into the resulting `config` set. Since this feature nullifies name +checking for entire option trees, it is only recommended for use in +submodules. + +::: {#ex-freeform-module .example} +::: {.title} +**Example: Freeform submodule** +::: +The following shows a submodule assigning a freeform type that allows +arbitrary attributes with `str` values below `settings`, but also +declares an option for the `settings.port` attribute to have it +type-checked and assign a default value. See +[Example: Declaring a type-checked `settings` attribute](#ex-settings-typed-attrs) +for a more complete example. + +```nix +{ lib, config, ... }: { + + options.settings = lib.mkOption { + type = lib.types.submodule { + + freeformType = with lib.types; attrsOf str; + + # We want this attribute to be checked for the correct type + options.port = lib.mkOption { + type = lib.types.port; + # Declaring the option also allows defining a default value + default = 8080; + }; + + }; + }; +} +``` + +And the following shows what such a module then allows + +```nix +{ + # Not a declared option, but the freeform type allows this + settings.logLevel = "debug"; + + # Not allowed because the the freeform type only allows strings + # settings.enable = true; + + # Allowed because there is a port option declared + settings.port = 80; + + # Not allowed because the port option doesn't allow strings + # settings.port = "443"; +} +``` +::: + +::: {.note} +Freeform attributes cannot depend on other attributes of the same set +without infinite recursion: + +```nix +{ + # This throws infinite recursion encountered + settings.logLevel = lib.mkIf (config.settings.port == 80) "debug"; +} +``` + +To prevent this, declare options for all attributes that need to depend +on others. For above example this means to declare `logLevel` to be an +option. +::: diff --git a/nixos/doc/manual/development/freeform-modules.xml b/nixos/doc/manual/development/freeform-modules.xml deleted file mode 100644 index 257e6b11bf01..000000000000 --- a/nixos/doc/manual/development/freeform-modules.xml +++ /dev/null @@ -1,68 +0,0 @@ -
- Freeform modules - - Freeform modules allow you to define values for option paths that have not been declared explicitly. This can be used to add attribute-specific types to what would otherwise have to be attrsOf options in order to accept all attribute names. - - - This feature can be enabled by using the attribute freeformType to define a freeform type. By doing this, all assignments without an associated option will be merged using the freeform type and combined into the resulting config set. Since this feature nullifies name checking for entire option trees, it is only recommended for use in submodules. - - - Freeform submodule - - The following shows a submodule assigning a freeform type that allows arbitrary attributes with str values below settings, but also declares an option for the settings.port attribute to have it type-checked and assign a default value. See for a more complete example. - - -{ lib, config, ... }: { - - options.settings = lib.mkOption { - type = lib.types.submodule { - - freeformType = with lib.types; attrsOf str; - - # We want this attribute to be checked for the correct type - options.port = lib.mkOption { - type = lib.types.port; - # Declaring the option also allows defining a default value - default = 8080; - }; - - }; - }; -} - - - And the following shows what such a module then allows - - -{ - # Not a declared option, but the freeform type allows this - settings.logLevel = "debug"; - - # Not allowed because the the freeform type only allows strings - # settings.enable = true; - - # Allowed because there is a port option declared - settings.port = 80; - - # Not allowed because the port option doesn't allow strings - # settings.port = "443"; -} - - - - - Freeform attributes cannot depend on other attributes of the same set without infinite recursion: - -{ - # This throws infinite recursion encountered - settings.logLevel = lib.mkIf (config.settings.port == 80) "debug"; -} - - To prevent this, declare options for all attributes that need to depend on others. For above example this means to declare logLevel to be an option. - - -
diff --git a/nixos/doc/manual/development/importing-modules.section.md b/nixos/doc/manual/development/importing-modules.section.md new file mode 100644 index 000000000000..65d78959b8e0 --- /dev/null +++ b/nixos/doc/manual/development/importing-modules.section.md @@ -0,0 +1,46 @@ +# Importing Modules {#sec-importing-modules} + +Sometimes NixOS modules need to be used in configuration but exist +outside of Nixpkgs. These modules can be imported: + +```nix +{ config, lib, pkgs, ... }: + +{ + imports = + [ # Use a locally-available module definition in + # ./example-module/default.nix + ./example-module + ]; + + services.exampleModule.enable = true; +} +``` + +The environment variable `NIXOS_EXTRA_MODULE_PATH` is an absolute path +to a NixOS module that is included alongside the Nixpkgs NixOS modules. +Like any NixOS module, this module can import additional modules: + +```nix +# ./module-list/default.nix +[ + ./example-module1 + ./example-module2 +] +``` + +```nix +# ./extra-module/default.nix +{ imports = import ./module-list.nix; } +``` + +```nix +# NIXOS_EXTRA_MODULE_PATH=/absolute/path/to/extra-module +{ config, lib, pkgs, ... }: + +{ + # No `imports` needed + + services.exampleModule1.enable = true; +} +``` diff --git a/nixos/doc/manual/development/importing-modules.xml b/nixos/doc/manual/development/importing-modules.xml deleted file mode 100644 index 1c6a5671eda8..000000000000 --- a/nixos/doc/manual/development/importing-modules.xml +++ /dev/null @@ -1,56 +0,0 @@ -
- Importing Modules - - - Sometimes NixOS modules need to be used in configuration but exist outside of - Nixpkgs. These modules can be imported: - - - -{ config, lib, pkgs, ... }: - -{ - imports = - [ # Use a locally-available module definition in - # ./example-module/default.nix - ./example-module - ]; - - services.exampleModule.enable = true; -} - - - - The environment variable NIXOS_EXTRA_MODULE_PATH is an - absolute path to a NixOS module that is included alongside the Nixpkgs NixOS - modules. Like any NixOS module, this module can import additional modules: - - - -# ./module-list/default.nix -[ - ./example-module1 - ./example-module2 -] - - - -# ./extra-module/default.nix -{ imports = import ./module-list.nix; } - - - -# NIXOS_EXTRA_MODULE_PATH=/absolute/path/to/extra-module -{ config, lib, pkgs, ... }: - -{ - # No `imports` needed - - services.exampleModule1.enable = true; -} - -
diff --git a/nixos/doc/manual/development/meta-attributes.section.md b/nixos/doc/manual/development/meta-attributes.section.md new file mode 100644 index 000000000000..ca4ba007f7dc --- /dev/null +++ b/nixos/doc/manual/development/meta-attributes.section.md @@ -0,0 +1,40 @@ +# Meta Attributes {#sec-meta-attributes} + +Like Nix packages, NixOS modules can declare meta-attributes to provide +extra information. Module meta attributes are defined in the `meta.nix` +special module. + +`meta` is a top level attribute like `options` and `config`. Available +meta-attributes are `maintainers` and `doc`. + +Each of the meta-attributes must be defined at most once per module +file. + +```nix +{ config, lib, pkgs, ... }: +{ + options = { + ... + }; + + config = { + ... + }; + + meta = { + maintainers = with lib.maintainers; [ ericsagnes ]; + doc = ./default.xml; + }; +} +``` + +- `maintainers` contains a list of the module maintainers. + +- `doc` points to a valid DocBook file containing the module + documentation. Its contents is automatically added to + [](#ch-configuration). Changes to a module documentation have to + be checked to not break building the NixOS manual: + + ```ShellSession + $ nix-build nixos/release.nix -A manual.x86_64-linux + ``` diff --git a/nixos/doc/manual/development/meta-attributes.xml b/nixos/doc/manual/development/meta-attributes.xml deleted file mode 100644 index c40be0a50c36..000000000000 --- a/nixos/doc/manual/development/meta-attributes.xml +++ /dev/null @@ -1,63 +0,0 @@ -
- Meta Attributes - - - Like Nix packages, NixOS modules can declare meta-attributes to provide extra - information. Module meta attributes are defined in the - meta.nix - special module. - - - - meta is a top level attribute like - options and config. Available - meta-attributes are maintainers and - doc. - - - - Each of the meta-attributes must be defined at most once per module file. - - - -{ config, lib, pkgs, ... }: -{ - options = { - ... - }; - - config = { - ... - }; - - meta = { - maintainers = with lib.maintainers; [ ericsagnes ]; - doc = ./default.xml; - }; -} - - - - - - maintainers contains a list of the module maintainers. - - - - - doc points to a valid DocBook file containing the module - documentation. Its contents is automatically added to - . Changes to a module documentation - have to be checked to not break building the NixOS manual: - -$ nix-build nixos/release.nix -A manual.x86_64-linux - - -
diff --git a/nixos/doc/manual/development/option-declarations.section.md b/nixos/doc/manual/development/option-declarations.section.md new file mode 100644 index 000000000000..819c23684cdf --- /dev/null +++ b/nixos/doc/manual/development/option-declarations.section.md @@ -0,0 +1,136 @@ +# Option Declarations {#sec-option-declarations} + +An option declaration specifies the name, type and description of a +NixOS configuration option. It is invalid to define an option that +hasn't been declared in any module. An option declaration generally +looks like this: + +```nix +options = { + name = mkOption { + type = type specification; + default = default value; + example = example value; + description = "Description for use in the NixOS manual."; + }; +}; +``` + +The attribute names within the `name` attribute path must be camel +cased in general but should, as an exception, match the [ package +attribute name](https://nixos.org/nixpkgs/manual/#sec-package-naming) +when referencing a Nixpkgs package. For example, the option +`services.nix-serve.bindAddress` references the `nix-serve` Nixpkgs +package. + +The function `mkOption` accepts the following arguments. + +`type` + +: The type of the option (see [](#sec-option-types)). It may be + omitted, but that's not advisable since it may lead to errors that + are hard to diagnose. + +`default` + +: The default value used if no value is defined by any module. A + default is not required; but if a default is not given, then users + of the module will have to define the value of the option, otherwise + an error will be thrown. + +`example` + +: An example value that will be shown in the NixOS manual. + +`description` + +: A textual description of the option, in DocBook format, that will be + included in the NixOS manual. + +## Extensible Option Types {#sec-option-declarations-eot} + +Extensible option types is a feature that allow to extend certain types +declaration through multiple module files. This feature only work with a +restricted set of types, namely `enum` and `submodules` and any composed +forms of them. + +Extensible option types can be used for `enum` options that affects +multiple modules, or as an alternative to related `enable` options. + +As an example, we will take the case of display managers. There is a +central display manager module for generic display manager options and a +module file per display manager backend (sddm, gdm \...). + +There are two approach to this module structure: + +- Managing the display managers independently by adding an enable + option to every display manager module backend. (NixOS) + +- Managing the display managers in the central module by adding an + option to select which display manager backend to use. + +Both approaches have problems. + +Making backends independent can quickly become hard to manage. For +display managers, there can be only one enabled at a time, but the type +system can not enforce this restriction as there is no relation between +each backend `enable` option. As a result, this restriction has to be +done explicitely by adding assertions in each display manager backend +module. + +On the other hand, managing the display managers backends in the central +module will require to change the central module option every time a new +backend is added or removed. + +By using extensible option types, it is possible to create a placeholder +option in the central module +([Example: Extensible type placeholder in the service module](#ex-option-declaration-eot-service)), +and to extend it in each backend module +([Example: Extending `services.xserver.displayManager.enable` in the `gdm` module](#ex-option-declaration-eot-backend-gdm), +[Example: Extending `services.xserver.displayManager.enable` in the `sddm` module](#ex-option-declaration-eot-backend-sddm)). + +As a result, `displayManager.enable` option values can be added without +changing the main service module file and the type system automatically +enforce that there can only be a single display manager enabled. + +::: {#ex-option-declaration-eot-service .example} +::: {.title} +**Example: Extensible type placeholder in the service module** +::: +```nix +services.xserver.displayManager.enable = mkOption { + description = "Display manager to use"; + type = with types; nullOr (enum [ ]); +}; +``` +::: + +::: {#ex-option-declaration-eot-backend-gdm .example} +::: {.title} +**Example: Extending `services.xserver.displayManager.enable` in the `gdm` module** +::: +```nix +services.xserver.displayManager.enable = mkOption { + type = with types; nullOr (enum [ "gdm" ]); +}; +``` +::: + +::: {#ex-option-declaration-eot-backend-sddm .example} +::: {.title} +**Example: Extending `services.xserver.displayManager.enable` in the `sddm` module** +::: +```nix +services.xserver.displayManager.enable = mkOption { + type = with types; nullOr (enum [ "sddm" ]); +}; +``` +::: + +The placeholder declaration is a standard `mkOption` declaration, but it +is important that extensible option declarations only use the `type` +argument. + +Extensible option types work with any of the composed variants of `enum` +such as `with types; nullOr (enum [ "foo" "bar" ])` or `with types; +listOf (enum [ "foo" "bar" ])`. diff --git a/nixos/doc/manual/development/option-declarations.xml b/nixos/doc/manual/development/option-declarations.xml deleted file mode 100644 index 56ebf4816306..000000000000 --- a/nixos/doc/manual/development/option-declarations.xml +++ /dev/null @@ -1,199 +0,0 @@ -
- Option Declarations - - - An option declaration specifies the name, type and description of a NixOS - configuration option. It is invalid to define an option that hasn’t been - declared in any module. An option declaration generally looks like this: - -options = { - name = mkOption { - type = type specification; - default = default value; - example = example value; - description = "Description for use in the NixOS manual."; - }; -}; - - The attribute names within the name attribute path - must be camel cased in general but should, as an exception, match the - - package attribute name when referencing a Nixpkgs package. For - example, the option services.nix-serve.bindAddress - references the nix-serve Nixpkgs package. - - - - The function mkOption accepts the following arguments. - - - - type - - - - The type of the option (see ). It may - be omitted, but that’s not advisable since it may lead to errors that - are hard to diagnose. - - - - - - default - - - - The default value used if no value is defined by any module. A default is - not required; but if a default is not given, then users of the module - will have to define the value of the option, otherwise an error will be - thrown. - - - - - - example - - - - An example value that will be shown in the NixOS manual. - - - - - - description - - - - A textual description of the option, in DocBook format, that will be - included in the NixOS manual. - - - - - - -
- Extensible Option Types - - - Extensible option types is a feature that allow to extend certain types - declaration through multiple module files. This feature only work with a - restricted set of types, namely enum and - submodules and any composed forms of them. - - - - Extensible option types can be used for enum options that - affects multiple modules, or as an alternative to related - enable options. - - - - As an example, we will take the case of display managers. There is a central - display manager module for generic display manager options and a module file - per display manager backend (sddm, gdm ...). - - - - There are two approach to this module structure: - - - - Managing the display managers independently by adding an enable option to - every display manager module backend. (NixOS) - - - - - Managing the display managers in the central module by adding an option - to select which display manager backend to use. - - - - - - - Both approaches have problems. - - - - Making backends independent can quickly become hard to manage. For display - managers, there can be only one enabled at a time, but the type system can - not enforce this restriction as there is no relation between each backend - enable option. As a result, this restriction has to be - done explicitely by adding assertions in each display manager backend - module. - - - - On the other hand, managing the display managers backends in the central - module will require to change the central module option every time a new - backend is added or removed. - - - - By using extensible option types, it is possible to create a placeholder - option in the central module - (), and to extend - it in each backend module - (, - ). - - - - As a result, displayManager.enable option values can be - added without changing the main service module file and the type system - automatically enforce that there can only be a single display manager - enabled. - - - - Extensible type placeholder in the service module - -services.xserver.displayManager.enable = mkOption { - description = "Display manager to use"; - type = with types; nullOr (enum [ ]); -}; - - - - Extending <literal>services.xserver.displayManager.enable</literal> in the <literal>gdm</literal> module - -services.xserver.displayManager.enable = mkOption { - type = with types; nullOr (enum [ "gdm" ]); -}; - - - - Extending <literal>services.xserver.displayManager.enable</literal> in the <literal>sddm</literal> module - -services.xserver.displayManager.enable = mkOption { - type = with types; nullOr (enum [ "sddm" ]); -}; - - - - The placeholder declaration is a standard mkOption - declaration, but it is important that extensible option declarations only - use the type argument. - - - - Extensible option types work with any of the composed variants of - enum such as with types; nullOr (enum [ "foo" - "bar" ]) or with types; listOf (enum [ "foo" "bar" - ]). - -
-
diff --git a/nixos/doc/manual/development/option-def.section.md b/nixos/doc/manual/development/option-def.section.md new file mode 100644 index 000000000000..91b24cd4a3a1 --- /dev/null +++ b/nixos/doc/manual/development/option-def.section.md @@ -0,0 +1,91 @@ +# Option Definitions {#sec-option-definitions} + +Option definitions are generally straight-forward bindings of values to +option names, like + +```nix +config = { + services.httpd.enable = true; +}; +``` + +However, sometimes you need to wrap an option definition or set of +option definitions in a *property* to achieve certain effects: + +## Delaying Conditionals {#sec-option-definitions-delaying-conditionals .unnumbered} + +If a set of option definitions is conditional on the value of another +option, you may need to use `mkIf`. Consider, for instance: + +```nix +config = if config.services.httpd.enable then { + environment.systemPackages = [ ... ]; + ... +} else {}; +``` + +This definition will cause Nix to fail with an "infinite recursion" +error. Why? Because the value of `config.services.httpd.enable` depends +on the value being constructed here. After all, you could also write the +clearly circular and contradictory: + +```nix +config = if config.services.httpd.enable then { + services.httpd.enable = false; +} else { + services.httpd.enable = true; +}; +``` + +The solution is to write: + +```nix +config = mkIf config.services.httpd.enable { + environment.systemPackages = [ ... ]; + ... +}; +``` + +The special function `mkIf` causes the evaluation of the conditional to +be "pushed down" into the individual definitions, as if you had written: + +```nix +config = { + environment.systemPackages = if config.services.httpd.enable then [ ... ] else []; + ... +}; +``` + +## Setting Priorities {#sec-option-definitions-setting-priorities .unnumbered} + +A module can override the definitions of an option in other modules by +setting a *priority*. All option definitions that do not have the lowest +priority value are discarded. By default, option definitions have +priority 1000. You can specify an explicit priority by using +`mkOverride`, e.g. + +```nix +services.openssh.enable = mkOverride 10 false; +``` + +This definition causes all other definitions with priorities above 10 to +be discarded. The function `mkForce` is equal to `mkOverride 50`. + +## Merging Configurations {#sec-option-definitions-merging .unnumbered} + +In conjunction with `mkIf`, it is sometimes useful for a module to +return multiple sets of option definitions, to be merged together as if +they were declared in separate modules. This can be done using +`mkMerge`: + +```nix +config = mkMerge + [ # Unconditional stuff. + { environment.systemPackages = [ ... ]; + } + # Conditional stuff. + (mkIf config.services.bla.enable { + environment.systemPackages = [ ... ]; + }) + ]; +``` diff --git a/nixos/doc/manual/development/option-def.xml b/nixos/doc/manual/development/option-def.xml deleted file mode 100644 index 50a705d0cb8e..000000000000 --- a/nixos/doc/manual/development/option-def.xml +++ /dev/null @@ -1,99 +0,0 @@ -
- Option Definitions - - - Option definitions are generally straight-forward bindings of values to - option names, like - -config = { - services.httpd.enable = true; -}; - - However, sometimes you need to wrap an option definition or set of option - definitions in a property to achieve certain effects: - - - - Delaying Conditionals - - If a set of option definitions is conditional on the value of another - option, you may need to use mkIf. Consider, for instance: - -config = if config.services.httpd.enable then { - environment.systemPackages = [ ... ]; - ... -} else {}; - - This definition will cause Nix to fail with an “infinite recursion” - error. Why? Because the value of - depends on the value being - constructed here. After all, you could also write the clearly circular and - contradictory: - -config = if config.services.httpd.enable then { - services.httpd.enable = false; -} else { - services.httpd.enable = true; -}; - - The solution is to write: - -config = mkIf config.services.httpd.enable { - environment.systemPackages = [ ... ]; - ... -}; - - The special function mkIf causes the evaluation of the - conditional to be “pushed down” into the individual definitions, as if - you had written: - -config = { - environment.systemPackages = if config.services.httpd.enable then [ ... ] else []; - ... -}; - - - - - - Setting Priorities - - A module can override the definitions of an option in other modules by - setting a priority. All option definitions that do not - have the lowest priority value are discarded. By default, option definitions - have priority 1000. You can specify an explicit priority by using - mkOverride, e.g. - -services.openssh.enable = mkOverride 10 false; - - This definition causes all other definitions with priorities above 10 to be - discarded. The function mkForce is equal to - mkOverride 50. - - - - - Merging Configurations - - In conjunction with mkIf, it is sometimes useful for a - module to return multiple sets of option definitions, to be merged together - as if they were declared in separate modules. This can be done using - mkMerge: - -config = mkMerge - [ # Unconditional stuff. - { environment.systemPackages = [ ... ]; - } - # Conditional stuff. - (mkIf config.services.bla.enable { - environment.systemPackages = [ ... ]; - }) - ]; - - - -
diff --git a/nixos/doc/manual/development/option-types.section.md b/nixos/doc/manual/development/option-types.section.md new file mode 100644 index 000000000000..ed557206659f --- /dev/null +++ b/nixos/doc/manual/development/option-types.section.md @@ -0,0 +1,558 @@ +# Options Types {#sec-option-types} + +Option types are a way to put constraints on the values a module option +can take. Types are also responsible of how values are merged in case of +multiple value definitions. + +## Basic Types {#sec-option-types-basic} + +Basic types are the simplest available types in the module system. Basic +types include multiple string types that mainly differ in how definition +merging is handled. + +`types.bool` + +: A boolean, its values can be `true` or `false`. + +`types.path` + +: A filesystem path, defined as anything that when coerced to a string + starts with a slash. Even if derivations can be considered as path, + the more specific `types.package` should be preferred. + +`types.package` + +: A derivation or a store path. + +`types.anything` + +: A type that accepts any value and recursively merges attribute sets + together. This type is recommended when the option type is unknown. + + ::: {#ex-types-anything .example} + ::: {.title} + **Example: `types.anything` Example** + ::: + Two definitions of this type like + + ```nix + { + str = lib.mkDefault "foo"; + pkg.hello = pkgs.hello; + fun.fun = x: x + 1; + } + ``` + + ```nix + { + str = lib.mkIf true "bar"; + pkg.gcc = pkgs.gcc; + fun.fun = lib.mkForce (x: x + 2); + } + ``` + + will get merged to + + ```nix + { + str = "bar"; + pkg.gcc = pkgs.gcc; + pkg.hello = pkgs.hello; + fun.fun = x: x + 2; + } + ``` + ::: + +`types.attrs` + +: A free-form attribute set. + + ::: {.warning} + This type will be deprecated in the future because it doesn\'t + recurse into attribute sets, silently drops earlier attribute + definitions, and doesn\'t discharge `lib.mkDefault`, `lib.mkIf` + and co. For allowing arbitrary attribute sets, prefer + `types.attrsOf types.anything` instead which doesn\'t have these + problems. + ::: + +Integer-related types: + +`types.int` + +: A signed integer. + +`types.ints.{s8, s16, s32}` + +: Signed integers with a fixed length (8, 16 or 32 bits). They go from + −2^n/2 to + 2^n/2−1 respectively (e.g. `−128` to + `127` for 8 bits). + +`types.ints.unsigned` + +: An unsigned integer (that is >= 0). + +`types.ints.{u8, u16, u32}` + +: Unsigned integers with a fixed length (8, 16 or 32 bits). They go + from 0 to 2^n−1 respectively (e.g. `0` + to `255` for 8 bits). + +`types.ints.positive` + +: A positive integer (that is > 0). + +`types.port` + +: A port number. This type is an alias to + `types.ints.u16`. + +String-related types: + +`types.str` + +: A string. Multiple definitions cannot be merged. + +`types.lines` + +: A string. Multiple definitions are concatenated with a new line + `"\n"`. + +`types.commas` + +: A string. Multiple definitions are concatenated with a comma `","`. + +`types.envVar` + +: A string. Multiple definitions are concatenated with a collon `":"`. + +`types.strMatching` + +: A string matching a specific regular expression. Multiple + definitions cannot be merged. The regular expression is processed + using `builtins.match`. + +## Value Types {#sec-option-types-value} + +Value types are types that take a value parameter. + +`types.enum` *`l`* + +: One element of the list *`l`*, e.g. `types.enum [ "left" "right" ]`. + Multiple definitions cannot be merged. + +`types.separatedString` *`sep`* + +: A string with a custom separator *`sep`*, e.g. + `types.separatedString "|"`. + +`types.ints.between` *`lowest highest`* + +: An integer between *`lowest`* and *`highest`* (both inclusive). Useful + for creating types like `types.port`. + +`types.submodule` *`o`* + +: A set of sub options *`o`*. *`o`* can be an attribute set, a function + returning an attribute set, or a path to a file containing such a + value. Submodules are used in composed types to create modular + options. This is equivalent to + `types.submoduleWith { modules = toList o; shorthandOnlyDefinesConfig = true; }`. + Submodules are detailed in [Submodule](#section-option-types-submodule). + +`types.submoduleWith` { *`modules`*, *`specialArgs`* ? {}, *`shorthandOnlyDefinesConfig`* ? false } + +: Like `types.submodule`, but more flexible and with better defaults. + It has parameters + + - *`modules`* A list of modules to use by default for this + submodule type. This gets combined with all option definitions + to build the final list of modules that will be included. + + ::: {.note} + Only options defined with this argument are included in rendered + documentation. + ::: + + - *`specialArgs`* An attribute set of extra arguments to be passed + to the module functions. The option `_module.args` should be + used instead for most arguments since it allows overriding. + *`specialArgs`* should only be used for arguments that can\'t go + through the module fixed-point, because of infinite recursion or + other problems. An example is overriding the `lib` argument, + because `lib` itself is used to define `_module.args`, which + makes using `_module.args` to define it impossible. + + - *`shorthandOnlyDefinesConfig`* Whether definitions of this type + should default to the `config` section of a module (see + [Example: Structure of NixOS Modules](#ex-module-syntax)) + if it is an attribute set. Enabling this only has a benefit + when the submodule defines an option named `config` or `options`. + In such a case it would allow the option to be set with + `the-submodule.config = "value"` instead of requiring + `the-submodule.config.config = "value"`. This is because + only when modules *don\'t* set the `config` or `options` + keys, all keys are interpreted as option definitions in the + `config` section. Enabling this option implicitly puts all + attributes in the `config` section. + + With this option enabled, defining a non-`config` section + requires using a function: + `the-submodule = { ... }: { options = { ... }; }`. + +## Composed Types {#sec-option-types-composed} + +Composed types are types that take a type as parameter. `listOf + int` and `either int str` are examples of composed types. + +`types.listOf` *`t`* + +: A list of *`t`* type, e.g. `types.listOf + int`. Multiple definitions are merged with list concatenation. + +`types.attrsOf` *`t`* + +: An attribute set of where all the values are of *`t`* type. Multiple + definitions result in the joined attribute set. + + ::: {.note} + This type is *strict* in its values, which in turn means attributes + cannot depend on other attributes. See ` + types.lazyAttrsOf` for a lazy version. + ::: + +`types.lazyAttrsOf` *`t`* + +: An attribute set of where all the values are of *`t`* type. Multiple + definitions result in the joined attribute set. This is the lazy + version of `types.attrsOf + `, allowing attributes to depend on each other. + + ::: {.warning} + This version does not fully support conditional definitions! With an + option `foo` of this type and a definition + `foo.attr = lib.mkIf false 10`, evaluating `foo ? attr` will return + `true` even though it should be false. Accessing the value will then + throw an error. For types *`t`* that have an `emptyValue` defined, + that value will be returned instead of throwing an error. So if the + type of `foo.attr` was `lazyAttrsOf (nullOr int)`, `null` would be + returned instead for the same `mkIf false` definition. + ::: + +`types.nullOr` *`t`* + +: `null` or type *`t`*. Multiple definitions are merged according to + type *`t`*. + +`types.uniq` *`t`* + +: Ensures that type *`t`* cannot be merged. It is used to ensure option + definitions are declared only once. + +`types.either` *`t1 t2`* + +: Type *`t1`* or type *`t2`*, e.g. `with types; either int str`. + Multiple definitions cannot be merged. + +`types.oneOf` \[ *`t1 t2`* \... \] + +: Type *`t1`* or type *`t2`* and so forth, e.g. + `with types; oneOf [ int str bool ]`. Multiple definitions cannot be + merged. + +`types.coercedTo` *`from f to`* + +: Type *`to`* or type *`from`* which will be coerced to type *`to`* using + function *`f`* which takes an argument of type *`from`* and return a + value of type *`to`*. Can be used to preserve backwards compatibility + of an option if its type was changed. + +## Submodule {#section-option-types-submodule} + +`submodule` is a very powerful type that defines a set of sub-options +that are handled like a separate module. + +It takes a parameter *`o`*, that should be a set, or a function returning +a set with an `options` key defining the sub-options. Submodule option +definitions are type-checked accordingly to the `options` declarations. +Of course, you can nest submodule option definitons for even higher +modularity. + +The option set can be defined directly +([Example: Directly defined submodule](#ex-submodule-direct)) or as reference +([Example: Submodule defined as a reference](#ex-submodule-reference)). + +::: {#ex-submodule-direct .example} +::: {.title} +**Example: Directly defined submodule** +::: +```nix +options.mod = mkOption { + description = "submodule example"; + type = with types; submodule { + options = { + foo = mkOption { + type = int; + }; + bar = mkOption { + type = str; + }; + }; + }; +}; +``` +::: + +::: {#ex-submodule-reference .example} +::: {.title} +**Example: Submodule defined as a reference** +::: +```nix +let + modOptions = { + options = { + foo = mkOption { + type = int; + }; + bar = mkOption { + type = int; + }; + }; + }; +in +options.mod = mkOption { + description = "submodule example"; + type = with types; submodule modOptions; +}; +``` +::: + +The `submodule` type is especially interesting when used with composed +types like `attrsOf` or `listOf`. When composed with `listOf` +([Example: Declaration of a list of submodules](#ex-submodule-listof-declaration)), `submodule` allows +multiple definitions of the submodule option set +([Example: Definition of a list of submodules](#ex-submodule-listof-definition)). + +::: {#ex-submodule-listof-declaration .example} +::: {.title} +**Example: Declaration of a list of submodules** +::: +```nix +options.mod = mkOption { + description = "submodule example"; + type = with types; listOf (submodule { + options = { + foo = mkOption { + type = int; + }; + bar = mkOption { + type = str; + }; + }; + }); +}; +``` +::: + +::: {#ex-submodule-listof-definition .example} +::: {.title} +**Example: Definition of a list of submodules** +::: +```nix +config.mod = [ + { foo = 1; bar = "one"; } + { foo = 2; bar = "two"; } +]; +``` +::: + +When composed with `attrsOf` +([Example: Declaration of attribute sets of submodules](#ex-submodule-attrsof-declaration)), `submodule` allows +multiple named definitions of the submodule option set +([Example: Definition of attribute sets of submodules](#ex-submodule-attrsof-definition)). + +::: {#ex-submodule-attrsof-declaration .example} +::: {.title} +**Example: Declaration of attribute sets of submodules** +::: +```nix +options.mod = mkOption { + description = "submodule example"; + type = with types; attrsOf (submodule { + options = { + foo = mkOption { + type = int; + }; + bar = mkOption { + type = str; + }; + }; + }); +}; +``` +::: + +::: {#ex-submodule-attrsof-definition .example} +::: {.title} +**Example: Definition of attribute sets of submodules** +::: +```nix +config.mod.one = { foo = 1; bar = "one"; }; +config.mod.two = { foo = 2; bar = "two"; }; +``` +::: + +## Extending types {#sec-option-types-extending} + +Types are mainly characterized by their `check` and `merge` functions. + +`check` + +: The function to type check the value. Takes a value as parameter and + return a boolean. It is possible to extend a type check with the + `addCheck` function ([Example: Adding a type check](#ex-extending-type-check-1)), + or to fully override the check function + ([Example: Overriding a type check](#ex-extending-type-check-2)). + + ::: {#ex-extending-type-check-1 .example} + ::: {.title} + **Example: Adding a type check** + ::: + ```nix + byte = mkOption { + description = "An integer between 0 and 255."; + type = types.addCheck types.int (x: x >= 0 && x <= 255); + }; + ``` + ::: + + ::: {#ex-extending-type-check-2 .example} + ::: {.title} + **Example: Overriding a type check** + ::: + ```nix + nixThings = mkOption { + description = "words that start with 'nix'"; + type = types.str // { + check = (x: lib.hasPrefix "nix" x) + }; + }; + ``` + ::: + +`merge` + +: Function to merge the options values when multiple values are set. + The function takes two parameters, `loc` the option path as a list + of strings, and `defs` the list of defined values as a list. It is + possible to override a type merge function for custom needs. + +## Custom Types {#sec-option-types-custom} + +Custom types can be created with the `mkOptionType` function. As type +creation includes some more complex topics such as submodule handling, +it is recommended to get familiar with `types.nix` code before creating +a new type. + +The only required parameter is `name`. + +`name` + +: A string representation of the type function name. + +`definition` + +: Description of the type used in documentation. Give information of + the type and any of its arguments. + +`check` + +: A function to type check the definition value. Takes the definition + value as a parameter and returns a boolean indicating the type check + result, `true` for success and `false` for failure. + +`merge` + +: A function to merge multiple definitions values. Takes two + parameters: + + *`loc`* + + : The option path as a list of strings, e.g. `["boot" "loader + "grub" "enable"]`. + + *`defs`* + + : The list of sets of defined `value` and `file` where the value + was defined, e.g. `[ { + file = "/foo.nix"; value = 1; } { file = "/bar.nix"; value = 2 } + ]`. The `merge` function should return the merged value + or throw an error in case the values are impossible or not meant + to be merged. + +`getSubOptions` + +: For composed types that can take a submodule as type parameter, this + function generate sub-options documentation. It takes the current + option prefix as a list and return the set of sub-options. Usually + defined in a recursive manner by adding a term to the prefix, e.g. + `prefix: + elemType.getSubOptions (prefix ++ + ["prefix"])` where *`"prefix"`* is the newly added prefix. + +`getSubModules` + +: For composed types that can take a submodule as type parameter, this + function should return the type parameters submodules. If the type + parameter is called `elemType`, the function should just recursively + look into submodules by returning `elemType.getSubModules;`. + +`substSubModules` + +: For composed types that can take a submodule as type parameter, this + function can be used to substitute the parameter of a submodule + type. It takes a module as parameter and return the type with the + submodule options substituted. It is usually defined as a type + function call with a recursive call to `substSubModules`, e.g for a + type `composedType` that take an `elemtype` type parameter, this + function should be defined as `m: + composedType (elemType.substSubModules m)`. + +`typeMerge` + +: A function to merge multiple type declarations. Takes the type to + merge `functor` as parameter. A `null` return value means that type + cannot be merged. + + *`f`* + + : The type to merge `functor`. + + Note: There is a generic `defaultTypeMerge` that work with most of + value and composed types. + +`functor` + +: An attribute set representing the type. It is used for type + operations and has the following keys: + + `type` + + : The type function. + + `wrapped` + + : Holds the type parameter for composed types. + + `payload` + + : Holds the value parameter for value types. The types that have a + `payload` are the `enum`, `separatedString` and `submodule` + types. + + `binOp` + + : A binary operation that can merge the payloads of two same + types. Defined as a function that take two payloads as + parameters and return the payloads merged. diff --git a/nixos/doc/manual/development/option-types.xml b/nixos/doc/manual/development/option-types.xml deleted file mode 100644 index 3d2191e2f3f3..000000000000 --- a/nixos/doc/manual/development/option-types.xml +++ /dev/null @@ -1,914 +0,0 @@ -
- Options Types - - - Option types are a way to put constraints on the values a module option can - take. Types are also responsible of how values are merged in case of multiple - value definitions. - - -
- Basic Types - - - Basic types are the simplest available types in the module system. Basic - types include multiple string types that mainly differ in how definition - merging is handled. - - - - - - types.bool - - - - A boolean, its values can be true or - false. - - - - - - types.path - - - - A filesystem path, defined as anything that when coerced to a string - starts with a slash. Even if derivations can be considered as path, the - more specific types.package should be preferred. - - - - - - types.package - - - - A derivation or a store path. - - - - - - types.anything - - - - A type that accepts any value and recursively merges attribute sets together. - This type is recommended when the option type is unknown. - - <literal>types.anything</literal> Example - - Two definitions of this type like - -{ - str = lib.mkDefault "foo"; - pkg.hello = pkgs.hello; - fun.fun = x: x + 1; -} - - -{ - str = lib.mkIf true "bar"; - pkg.gcc = pkgs.gcc; - fun.fun = lib.mkForce (x: x + 2); -} - - will get merged to - -{ - str = "bar"; - pkg.gcc = pkgs.gcc; - pkg.hello = pkgs.hello; - fun.fun = x: x + 2; -} - - - - - - - - - types.attrs - - - - A free-form attribute set. - - This type will be deprecated in the future because it doesn't recurse - into attribute sets, silently drops earlier attribute definitions, and - doesn't discharge lib.mkDefault, lib.mkIf - and co. For allowing arbitrary attribute sets, prefer - types.attrsOf types.anything instead which doesn't - have these problems. - - - - - - - - Integer-related types: - - - - - - types.int - - - - A signed integer. - - - - - - types.ints.{s8, s16, s32} - - - - Signed integers with a fixed length (8, 16 or 32 bits). They go from - −2n/2 - to - 2n/2−1 - respectively (e.g. −128 to - 127 for 8 bits). - - - - - - types.ints.unsigned - - - - An unsigned integer (that is >= 0). - - - - - - types.ints.{u8, u16, u32} - - - - Unsigned integers with a fixed length (8, 16 or 32 bits). They go from - 0 to - - 2n−1 - respectively (e.g. 0 to - 255 for 8 bits). - - - - - - types.ints.positive - - - - A positive integer (that is > 0). - - - - - - types.port - - - - A port number. This type is an alias to - types.ints.u16. - - - - - - - String-related types: - - - - - - types.str - - - - A string. Multiple definitions cannot be merged. - - - - - - types.lines - - - - A string. Multiple definitions are concatenated with a new line - "\n". - - - - - - types.commas - - - - A string. Multiple definitions are concatenated with a comma - ",". - - - - - - types.envVar - - - - A string. Multiple definitions are concatenated with a collon - ":". - - - - - - types.strMatching - - - - A string matching a specific regular expression. Multiple definitions - cannot be merged. The regular expression is processed using - builtins.match. - - - - -
- -
- Value Types - - - Value types are types that take a value parameter. - - - - - - types.enum l - - - - One element of the list l, e.g. - types.enum [ "left" "right" ]. Multiple definitions - cannot be merged. - - - - - - types.separatedString sep - - - - A string with a custom separator sep, e.g. - types.separatedString "|". - - - - - - types.ints.between lowest highest - - - - An integer between lowest and - highest (both inclusive). Useful for creating - types like types.port. - - - - - - types.submodule o - - - - A set of sub options o. - o can be an attribute set, a function - returning an attribute set, or a path to a file containing such a value. Submodules are used in - composed types to create modular options. This is equivalent to - types.submoduleWith { modules = toList o; shorthandOnlyDefinesConfig = true; }. - Submodules are detailed in - . - - - - - - types.submoduleWith { - modules, - specialArgs ? {}, - shorthandOnlyDefinesConfig ? false } - - - - Like types.submodule, but more flexible and with better defaults. - It has parameters - - - modules - A list of modules to use by default for this submodule type. This gets combined - with all option definitions to build the final list of modules that will be included. - - Only options defined with this argument are included in rendered documentation. - - - - specialArgs - An attribute set of extra arguments to be passed to the module functions. - The option _module.args should be used instead - for most arguments since it allows overriding. specialArgs should only be - used for arguments that can't go through the module fixed-point, because of - infinite recursion or other problems. An example is overriding the - lib argument, because lib itself is used - to define _module.args, which makes using - _module.args to define it impossible. - - - shorthandOnlyDefinesConfig - Whether definitions of this type should default to the config - section of a module (see ) if it is an attribute - set. Enabling this only has a benefit when the submodule defines an option named - config or options. In such a case it would - allow the option to be set with the-submodule.config = "value" - instead of requiring the-submodule.config.config = "value". - This is because only when modules don't set the - config or options keys, all keys are interpreted - as option definitions in the config section. Enabling this option - implicitly puts all attributes in the config section. - - - With this option enabled, defining a non-config section requires - using a function: the-submodule = { ... }: { options = { ... }; }. - - - - - - -
- -
- Composed Types - - - Composed types are types that take a type as parameter. listOf - int and either int str are examples of composed - types. - - - - - - types.listOf t - - - - A list of t type, e.g. types.listOf - int. Multiple definitions are merged with list concatenation. - - - - - - types.attrsOf t - - - - An attribute set of where all the values are of - t type. Multiple definitions result in the - joined attribute set. - - This type is strict in its values, which in turn - means attributes cannot depend on other attributes. See - types.lazyAttrsOf for a lazy version. - - - - - - - types.lazyAttrsOf t - - - - An attribute set of where all the values are of - t type. Multiple definitions result in the - joined attribute set. This is the lazy version of types.attrsOf - , allowing attributes to depend on each other. - - This version does not fully support conditional definitions! With an - option foo of this type and a definition - foo.attr = lib.mkIf false 10, evaluating - foo ? attr will return true - even though it should be false. Accessing the value will then throw - an error. For types t that have an - emptyValue defined, that value will be returned - instead of throwing an error. So if the type of foo.attr - was lazyAttrsOf (nullOr int), null - would be returned instead for the same mkIf false definition. - - - - - - - types.nullOr t - - - - null or type t. Multiple - definitions are merged according to type t. - - - - - - types.uniq t - - - - Ensures that type t cannot be merged. It is - used to ensure option definitions are declared only once. - - - - - - types.either t1 t2 - - - - Type t1 or type t2, - e.g. with types; either int str. Multiple definitions - cannot be merged. - - - - - - types.oneOf [ t1 t2 ... ] - - - - Type t1 or type t2 and so forth, - e.g. with types; oneOf [ int str bool ]. Multiple definitions - cannot be merged. - - - - - - types.coercedTo from f to - - - - Type to or type - from which will be coerced to type - to using function f - which takes an argument of type from and - return a value of type to. Can be used to - preserve backwards compatibility of an option if its type was changed. - - - - -
- -
- Submodule - - - submodule is a very powerful type that defines a set of - sub-options that are handled like a separate module. - - - - It takes a parameter o, that should be a set, or - a function returning a set with an options key defining - the sub-options. Submodule option definitions are type-checked accordingly - to the options declarations. Of course, you can nest - submodule option definitons for even higher modularity. - - - - The option set can be defined directly - () or as reference - (). - - - - Directly defined submodule - -options.mod = mkOption { - description = "submodule example"; - type = with types; submodule { - options = { - foo = mkOption { - type = int; - }; - bar = mkOption { - type = str; - }; - }; - }; -}; - - - - Submodule defined as a reference - -let - modOptions = { - options = { - foo = mkOption { - type = int; - }; - bar = mkOption { - type = int; - }; - }; - }; -in -options.mod = mkOption { - description = "submodule example"; - type = with types; submodule modOptions; -}; - - - - The submodule type is especially interesting when used - with composed types like attrsOf or - listOf. When composed with listOf - (), - submodule allows multiple definitions of the submodule - option set (). - - - - Declaration of a list of submodules - -options.mod = mkOption { - description = "submodule example"; - type = with types; listOf (submodule { - options = { - foo = mkOption { - type = int; - }; - bar = mkOption { - type = str; - }; - }; - }); -}; - - - - Definition of a list of submodules - -config.mod = [ - { foo = 1; bar = "one"; } - { foo = 2; bar = "two"; } -]; - - - - When composed with attrsOf - (), - submodule allows multiple named definitions of the - submodule option set (). - - - - Declaration of attribute sets of submodules - -options.mod = mkOption { - description = "submodule example"; - type = with types; attrsOf (submodule { - options = { - foo = mkOption { - type = int; - }; - bar = mkOption { - type = str; - }; - }; - }); -}; - - - - Declaration of attribute sets of submodules - -config.mod.one = { foo = 1; bar = "one"; }; -config.mod.two = { foo = 2; bar = "two"; }; - -
- -
- Extending types - - - Types are mainly characterized by their check and - merge functions. - - - - - - check - - - - The function to type check the value. Takes a value as parameter and - return a boolean. It is possible to extend a type check with the - addCheck function - (), or to fully - override the check function - (). - - - Adding a type check - -byte = mkOption { - description = "An integer between 0 and 255."; - type = types.addCheck types.int (x: x >= 0 && x <= 255); -}; - - - Overriding a type check - -nixThings = mkOption { - description = "words that start with 'nix'"; - type = types.str // { - check = (x: lib.hasPrefix "nix" x) - }; -}; - - - - - - merge - - - - Function to merge the options values when multiple values are set. The - function takes two parameters, loc the option path as - a list of strings, and defs the list of defined values - as a list. It is possible to override a type merge function for custom - needs. - - - - -
- -
- Custom Types - - - Custom types can be created with the mkOptionType - function. As type creation includes some more complex topics such as - submodule handling, it is recommended to get familiar with - types.nix - code before creating a new type. - - - - The only required parameter is name. - - - - - - name - - - - A string representation of the type function name. - - - - - - definition - - - - Description of the type used in documentation. Give information of the - type and any of its arguments. - - - - - - check - - - - A function to type check the definition value. Takes the definition value - as a parameter and returns a boolean indicating the type check result, - true for success and false for - failure. - - - - - - merge - - - - A function to merge multiple definitions values. Takes two parameters: - - - - - loc - - - - The option path as a list of strings, e.g. ["boot" "loader - "grub" "enable"]. - - - - - - defs - - - - The list of sets of defined value and - file where the value was defined, e.g. [ { - file = "/foo.nix"; value = 1; } { file = "/bar.nix"; value = 2 } - ]. The merge function should return the - merged value or throw an error in case the values are impossible or - not meant to be merged. - - - - - - - - - getSubOptions - - - - For composed types that can take a submodule as type parameter, this - function generate sub-options documentation. It takes the current option - prefix as a list and return the set of sub-options. Usually defined in a - recursive manner by adding a term to the prefix, e.g. prefix: - elemType.getSubOptions (prefix ++ - ["prefix"]) where - "prefix" is the newly added prefix. - - - - - - getSubModules - - - - For composed types that can take a submodule as type parameter, this - function should return the type parameters submodules. If the type - parameter is called elemType, the function should just - recursively look into submodules by returning - elemType.getSubModules;. - - - - - - substSubModules - - - - For composed types that can take a submodule as type parameter, this - function can be used to substitute the parameter of a submodule type. It - takes a module as parameter and return the type with the submodule - options substituted. It is usually defined as a type function call with a - recursive call to substSubModules, e.g for a type - composedType that take an elemtype - type parameter, this function should be defined as m: - composedType (elemType.substSubModules m). - - - - - - typeMerge - - - - A function to merge multiple type declarations. Takes the type to merge - functor as parameter. A null return - value means that type cannot be merged. - - - - - f - - - - The type to merge functor. - - - - - - Note: There is a generic defaultTypeMerge that work - with most of value and composed types. - - - - - - functor - - - - An attribute set representing the type. It is used for type operations - and has the following keys: - - - - - type - - - - The type function. - - - - - - wrapped - - - - Holds the type parameter for composed types. - - - - - - payload - - - - Holds the value parameter for value types. The types that have a - payload are the enum, - separatedString and submodule - types. - - - - - - binOp - - - - A binary operation that can merge the payloads of two same types. - Defined as a function that take two payloads as parameters and return - the payloads merged. - - - - - - - -
-
diff --git a/nixos/doc/manual/development/replace-modules.section.md b/nixos/doc/manual/development/replace-modules.section.md new file mode 100644 index 000000000000..0700a82004c1 --- /dev/null +++ b/nixos/doc/manual/development/replace-modules.section.md @@ -0,0 +1,64 @@ +# Replace Modules {#sec-replace-modules} + +Modules that are imported can also be disabled. The option declarations, +config implementation and the imports of a disabled module will be +ignored, allowing another to take it\'s place. This can be used to +import a set of modules from another channel while keeping the rest of +the system on a stable release. + +`disabledModules` is a top level attribute like `imports`, `options` and +`config`. It contains a list of modules that will be disabled. This can +either be the full path to the module or a string with the filename +relative to the modules path (eg. \ for nixos). + +This example will replace the existing postgresql module with the +version defined in the nixos-unstable channel while keeping the rest of +the modules and packages from the original nixos channel. This only +overrides the module definition, this won\'t use postgresql from +nixos-unstable unless explicitly configured to do so. + +```nix +{ config, lib, pkgs, ... }: + +{ + disabledModules = [ "services/databases/postgresql.nix" ]; + + imports = + [ # Use postgresql service from nixos-unstable channel. + # sudo nix-channel --add https://nixos.org/channels/nixos-unstable nixos-unstable + + ]; + + services.postgresql.enable = true; +} +``` + +This example shows how to define a custom module as a replacement for an +existing module. Importing this module will disable the original module +without having to know it\'s implementation details. + +```nix +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.man; +in + +{ + disabledModules = [ "services/programs/man.nix" ]; + + options = { + programs.man.enable = mkOption { + type = types.bool; + default = true; + description = "Whether to enable manual pages."; + }; + }; + + config = mkIf cfg.enabled { + warnings = [ "disabled manpages for production deployments." ]; + }; +} +``` diff --git a/nixos/doc/manual/development/replace-modules.xml b/nixos/doc/manual/development/replace-modules.xml deleted file mode 100644 index 9fc5678ca1b3..000000000000 --- a/nixos/doc/manual/development/replace-modules.xml +++ /dev/null @@ -1,79 +0,0 @@ -
- Replace Modules - - - Modules that are imported can also be disabled. The option declarations, - config implementation and the imports of a disabled module will be ignored, allowing another - to take it's place. This can be used to import a set of modules from another - channel while keeping the rest of the system on a stable release. - - - - disabledModules is a top level attribute like - imports, options and - config. It contains a list of modules that will be - disabled. This can either be the full path to the module or a string with the - filename relative to the modules path (eg. <nixpkgs/nixos/modules> for - nixos). - - - - This example will replace the existing postgresql module with the version - defined in the nixos-unstable channel while keeping the rest of the modules - and packages from the original nixos channel. This only overrides the module - definition, this won't use postgresql from nixos-unstable unless explicitly - configured to do so. - - - -{ config, lib, pkgs, ... }: - -{ - disabledModules = [ "services/databases/postgresql.nix" ]; - - imports = - [ # Use postgresql service from nixos-unstable channel. - # sudo nix-channel --add https://nixos.org/channels/nixos-unstable nixos-unstable - <nixos-unstable/nixos/modules/services/databases/postgresql.nix> - ]; - - services.postgresql.enable = true; -} - - - - This example shows how to define a custom module as a replacement for an - existing module. Importing this module will disable the original module - without having to know it's implementation details. - - - -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.programs.man; -in - -{ - disabledModules = [ "services/programs/man.nix" ]; - - options = { - programs.man.enable = mkOption { - type = types.bool; - default = true; - description = "Whether to enable manual pages."; - }; - }; - - config = mkIf cfg.enabled { - warnings = [ "disabled manpages for production deployments." ]; - }; -} - -
diff --git a/nixos/doc/manual/development/settings-options.section.md b/nixos/doc/manual/development/settings-options.section.md new file mode 100644 index 000000000000..58a3d8448af5 --- /dev/null +++ b/nixos/doc/manual/development/settings-options.section.md @@ -0,0 +1,192 @@ +# Options for Program Settings {#sec-settings-options} + +Many programs have configuration files where program-specific settings +can be declared. File formats can be separated into two categories: + +- Nix-representable ones: These can trivially be mapped to a subset of + Nix syntax. E.g. JSON is an example, since its values like + `{"foo":{"bar":10}}` can be mapped directly to Nix: + `{ foo = { bar = 10; }; }`. Other examples are INI, YAML and TOML. + The following section explains the convention for these settings. + +- Non-nix-representable ones: These can\'t be trivially mapped to a + subset of Nix syntax. Most generic programming languages are in this + group, e.g. bash, since the statement `if true; then echo hi; fi` + doesn\'t have a trivial representation in Nix. + + Currently there are no fixed conventions for these, but it is common + to have a `configFile` option for setting the configuration file + path directly. The default value of `configFile` can be an + auto-generated file, with convenient options for controlling the + contents. For example an option of type `attrsOf str` can be used + for representing environment variables which generates a section + like `export FOO="foo"`. Often it can also be useful to also include + an `extraConfig` option of type `lines` to allow arbitrary text + after the autogenerated part of the file. + +## Nix-representable Formats (JSON, YAML, TOML, INI, \...) {#sec-settings-nix-representable} + +By convention, formats like this are handled with a generic `settings` +option, representing the full program configuration as a Nix value. The +type of this option should represent the format. The most common formats +have a predefined type and string generator already declared under +`pkgs.formats`: + +`pkgs.formats.json` { } + +: A function taking an empty attribute set (for future extensibility) + and returning a set with JSON-specific attributes `type` and + `generate` as specified [below](#pkgs-formats-result). + +`pkgs.formats.yaml` { } + +: A function taking an empty attribute set (for future extensibility) + and returning a set with YAML-specific attributes `type` and + `generate` as specified [below](#pkgs-formats-result). + +`pkgs.formats.ini` { *`listsAsDuplicateKeys`* ? false, *`listToValue`* ? null, \... } + +: A function taking an attribute set with values + + `listsAsDuplicateKeys` + + : A boolean for controlling whether list values can be used to + represent duplicate INI keys + + `listToValue` + + : A function for turning a list of values into a single value. + + It returns a set with INI-specific attributes `type` and `generate` + as specified [below](#pkgs-formats-result). + +`pkgs.formats.toml` { } + +: A function taking an empty attribute set (for future extensibility) + and returning a set with TOML-specific attributes `type` and + `generate` as specified [below](#pkgs-formats-result). + +::: {#pkgs-formats-result} +These functions all return an attribute set with these values: +::: + +`type` + +: A module system type representing a value of the format + +`generate` *`filename jsonValue`* + +: A function that can render a value of the format to a file. Returns + a file path. + + ::: {.note} + This function puts the value contents in the Nix store. So this + should be avoided for secrets. + ::: + +::: {#ex-settings-nix-representable .example} +::: {.title} +**Example: Module with conventional `settings` option** +::: +The following shows a module for an example program that uses a JSON +configuration file. It demonstrates how above values can be used, along +with some other related best practices. See the comments for +explanations. + +```nix +{ options, config, lib, pkgs, ... }: +let + cfg = config.services.foo; + # Define the settings format used for this program + settingsFormat = pkgs.formats.json {}; +in { + + options.services.foo = { + enable = lib.mkEnableOption "foo service"; + + settings = lib.mkOption { + # Setting this type allows for correct merging behavior + type = settingsFormat.type; + default = {}; + description = '' + Configuration for foo, see + + for supported settings. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + # We can assign some default settings here to make the service work by just + # enabling it. We use `mkDefault` for values that can be changed without + # problems + services.foo.settings = { + # Fails at runtime without any value set + log_level = lib.mkDefault "WARN"; + + # We assume systemd's `StateDirectory` is used, so we require this value, + # therefore no mkDefault + data_path = "/var/lib/foo"; + + # Since we use this to create a user we need to know the default value at + # eval time + user = lib.mkDefault "foo"; + }; + + environment.etc."foo.json".source = + # The formats generator function takes a filename and the Nix value + # representing the format value and produces a filepath with that value + # rendered in the format + settingsFormat.generate "foo-config.json" cfg.settings; + + # We know that the `user` attribute exists because we set a default value + # for it above, allowing us to use it without worries here + users.users.${cfg.settings.user} = { isSystemUser = true; }; + + # ... + }; +} +``` +::: + +### Option declarations for attributes {#sec-settings-attrs-options} + +Some `settings` attributes may deserve some extra care. They may need a +different type, default or merging behavior, or they are essential +options that should show their documentation in the manual. This can be +done using [](#sec-freeform-modules). + +We extend above example using freeform modules to declare an option for +the port, which will enforce it to be a valid integer and make it show +up in the manual. + +::: {#ex-settings-typed-attrs .example} +::: {.title} +**Example: Declaring a type-checked `settings` attribute** +::: +```nix +settings = lib.mkOption { + type = lib.types.submodule { + + freeformType = settingsFormat.type; + + # Declare an option for the port such that the type is checked and this option + # is shown in the manual. + options.port = lib.mkOption { + type = lib.types.port; + default = 8080; + description = '' + Which port this service should listen on. + ''; + }; + + }; + default = {}; + description = '' + Configuration for Foo, see + + for supported values. + ''; +}; +``` +::: diff --git a/nixos/doc/manual/development/settings-options.xml b/nixos/doc/manual/development/settings-options.xml deleted file mode 100644 index 7292cac62b70..000000000000 --- a/nixos/doc/manual/development/settings-options.xml +++ /dev/null @@ -1,226 +0,0 @@ -
- Options for Program Settings - - - Many programs have configuration files where program-specific settings can be declared. File formats can be separated into two categories: - - - - Nix-representable ones: These can trivially be mapped to a subset of Nix syntax. E.g. JSON is an example, since its values like {"foo":{"bar":10}} can be mapped directly to Nix: { foo = { bar = 10; }; }. Other examples are INI, YAML and TOML. The following section explains the convention for these settings. - - - - - Non-nix-representable ones: These can't be trivially mapped to a subset of Nix syntax. Most generic programming languages are in this group, e.g. bash, since the statement if true; then echo hi; fi doesn't have a trivial representation in Nix. - - - Currently there are no fixed conventions for these, but it is common to have a configFile option for setting the configuration file path directly. The default value of configFile can be an auto-generated file, with convenient options for controlling the contents. For example an option of type attrsOf str can be used for representing environment variables which generates a section like export FOO="foo". Often it can also be useful to also include an extraConfig option of type lines to allow arbitrary text after the autogenerated part of the file. - - - - -
- Nix-representable Formats (JSON, YAML, TOML, INI, ...) - - By convention, formats like this are handled with a generic settings option, representing the full program configuration as a Nix value. The type of this option should represent the format. The most common formats have a predefined type and string generator already declared under pkgs.formats: - - - - pkgs.formats.json { } - - - - A function taking an empty attribute set (for future extensibility) and returning a set with JSON-specific attributes type and generate as specified below. - - - - - - pkgs.formats.yaml { } - - - - A function taking an empty attribute set (for future extensibility) and returning a set with YAML-specific attributes type and generate as specified below. - - - - - - pkgs.formats.ini { listsAsDuplicateKeys ? false, listToValue ? null, ... } - - - - A function taking an attribute set with values - - - - listsAsDuplicateKeys - - - - A boolean for controlling whether list values can be used to represent duplicate INI keys - - - - - - listToValue - - - - A function for turning a list of values into a single value. - - - - - It returns a set with INI-specific attributes type and generate as specified below. - - - - - - pkgs.formats.toml { } - - - - A function taking an empty attribute set (for future extensibility) and returning a set with TOML-specific attributes type and generate as specified below. - - - - - - - - These functions all return an attribute set with these values: - - - - type - - - - A module system type representing a value of the format - - - - - - generate filename jsonValue - - - - A function that can render a value of the format to a file. Returns a file path. - - - This function puts the value contents in the Nix store. So this should be avoided for secrets. - - - - - - - - - Module with conventional <literal>settings</literal> option - - The following shows a module for an example program that uses a JSON configuration file. It demonstrates how above values can be used, along with some other related best practices. See the comments for explanations. - - -{ options, config, lib, pkgs, ... }: -let - cfg = config.services.foo; - # Define the settings format used for this program - settingsFormat = pkgs.formats.json {}; -in { - - options.services.foo = { - enable = lib.mkEnableOption "foo service"; - - settings = lib.mkOption { - # Setting this type allows for correct merging behavior - type = settingsFormat.type; - default = {}; - description = '' - Configuration for foo, see - <link xlink:href="https://example.com/docs/foo"/> - for supported settings. - ''; - }; - }; - - config = lib.mkIf cfg.enable { - # We can assign some default settings here to make the service work by just - # enabling it. We use `mkDefault` for values that can be changed without - # problems - services.foo.settings = { - # Fails at runtime without any value set - log_level = lib.mkDefault "WARN"; - - # We assume systemd's `StateDirectory` is used, so we require this value, - # therefore no mkDefault - data_path = "/var/lib/foo"; - - # Since we use this to create a user we need to know the default value at - # eval time - user = lib.mkDefault "foo"; - }; - - environment.etc."foo.json".source = - # The formats generator function takes a filename and the Nix value - # representing the format value and produces a filepath with that value - # rendered in the format - settingsFormat.generate "foo-config.json" cfg.settings; - - # We know that the `user` attribute exists because we set a default value - # for it above, allowing us to use it without worries here - users.users.${cfg.settings.user} = { isSystemUser = true; }; - - # ... - }; -} - - -
- Option declarations for attributes - - Some settings attributes may deserve some extra care. They may need a different type, default or merging behavior, or they are essential options that should show their documentation in the manual. This can be done using . - - Declaring a type-checked <literal>settings</literal> attribute - - We extend above example using freeform modules to declare an option for the port, which will enforce it to be a valid integer and make it show up in the manual. - - -settings = lib.mkOption { - type = lib.types.submodule { - - freeformType = settingsFormat.type; - - # Declare an option for the port such that the type is checked and this option - # is shown in the manual. - options.port = lib.mkOption { - type = lib.types.port; - default = 8080; - description = '' - Which port this service should listen on. - ''; - }; - - }; - default = {}; - description = '' - Configuration for Foo, see - <link xlink:href="https://example.com/docs/foo"/> - for supported values. - ''; -}; - - - -
-
- -
diff --git a/nixos/doc/manual/development/writing-modules.xml b/nixos/doc/manual/development/writing-modules.xml index 04497db77b89..167976247091 100644 --- a/nixos/doc/manual/development/writing-modules.xml +++ b/nixos/doc/manual/development/writing-modules.xml @@ -179,13 +179,13 @@ in { } - - - + + + - - - - - + + + + + diff --git a/nixos/doc/manual/from_md/development/freeform-modules.section.xml b/nixos/doc/manual/from_md/development/freeform-modules.section.xml new file mode 100644 index 000000000000..86a9cf3140d8 --- /dev/null +++ b/nixos/doc/manual/from_md/development/freeform-modules.section.xml @@ -0,0 +1,87 @@ +
+ Freeform modules + + Freeform modules allow you to define values for option paths that + have not been declared explicitly. This can be used to add + attribute-specific types to what would otherwise have to be + attrsOf options in order to accept all attribute + names. + + + This feature can be enabled by using the attribute + freeformType to define a freeform type. By doing + this, all assignments without an associated option will be merged + using the freeform type and combined into the resulting + config set. Since this feature nullifies name + checking for entire option trees, it is only recommended for use in + submodules. + + + + Example: Freeform submodule + + + The following shows a submodule assigning a freeform type that + allows arbitrary attributes with str values below + settings, but also declares an option for the + settings.port attribute to have it type-checked + and assign a default value. See + Example: Declaring a + type-checked settings attribute for a more + complete example. + + +{ lib, config, ... }: { + + options.settings = lib.mkOption { + type = lib.types.submodule { + + freeformType = with lib.types; attrsOf str; + + # We want this attribute to be checked for the correct type + options.port = lib.mkOption { + type = lib.types.port; + # Declaring the option also allows defining a default value + default = 8080; + }; + + }; + }; +} + + + And the following shows what such a module then allows + + +{ + # Not a declared option, but the freeform type allows this + settings.logLevel = "debug"; + + # Not allowed because the the freeform type only allows strings + # settings.enable = true; + + # Allowed because there is a port option declared + settings.port = 80; + + # Not allowed because the port option doesn't allow strings + # settings.port = "443"; +} + + + + Freeform attributes cannot depend on other attributes of the same + set without infinite recursion: + + +{ + # This throws infinite recursion encountered + settings.logLevel = lib.mkIf (config.settings.port == 80) "debug"; +} + + + To prevent this, declare options for all attributes that need to + depend on others. For above example this means to declare + logLevel to be an option. + + +
diff --git a/nixos/doc/manual/from_md/development/importing-modules.section.xml b/nixos/doc/manual/from_md/development/importing-modules.section.xml new file mode 100644 index 000000000000..cb04dde67c83 --- /dev/null +++ b/nixos/doc/manual/from_md/development/importing-modules.section.xml @@ -0,0 +1,47 @@ +
+ Importing Modules + + Sometimes NixOS modules need to be used in configuration but exist + outside of Nixpkgs. These modules can be imported: + + +{ config, lib, pkgs, ... }: + +{ + imports = + [ # Use a locally-available module definition in + # ./example-module/default.nix + ./example-module + ]; + + services.exampleModule.enable = true; +} + + + The environment variable NIXOS_EXTRA_MODULE_PATH + is an absolute path to a NixOS module that is included alongside the + Nixpkgs NixOS modules. Like any NixOS module, this module can import + additional modules: + + +# ./module-list/default.nix +[ + ./example-module1 + ./example-module2 +] + + +# ./extra-module/default.nix +{ imports = import ./module-list.nix; } + + +# NIXOS_EXTRA_MODULE_PATH=/absolute/path/to/extra-module +{ config, lib, pkgs, ... }: + +{ + # No `imports` needed + + services.exampleModule1.enable = true; +} + +
diff --git a/nixos/doc/manual/from_md/development/meta-attributes.section.xml b/nixos/doc/manual/from_md/development/meta-attributes.section.xml new file mode 100644 index 000000000000..f535d94602bd --- /dev/null +++ b/nixos/doc/manual/from_md/development/meta-attributes.section.xml @@ -0,0 +1,55 @@ +
+ Meta Attributes + + Like Nix packages, NixOS modules can declare meta-attributes to + provide extra information. Module meta attributes are defined in the + meta.nix special module. + + + meta is a top level attribute like + options and config. Available + meta-attributes are maintainers and + doc. + + + Each of the meta-attributes must be defined at most once per module + file. + + +{ config, lib, pkgs, ... }: +{ + options = { + ... + }; + + config = { + ... + }; + + meta = { + maintainers = with lib.maintainers; [ ericsagnes ]; + doc = ./default.xml; + }; +} + + + + + maintainers contains a list of the module + maintainers. + + + + + doc points to a valid DocBook file containing + the module documentation. Its contents is automatically added to + . Changes to a module + documentation have to be checked to not break building the NixOS + manual: + + +$ nix-build nixos/release.nix -A manual.x86_64-linux + + + +
diff --git a/nixos/doc/manual/from_md/development/option-declarations.section.xml b/nixos/doc/manual/from_md/development/option-declarations.section.xml new file mode 100644 index 000000000000..85a59a543d14 --- /dev/null +++ b/nixos/doc/manual/from_md/development/option-declarations.section.xml @@ -0,0 +1,203 @@ +
+ Option Declarations + + An option declaration specifies the name, type and description of a + NixOS configuration option. It is invalid to define an option that + hasn’t been declared in any module. An option declaration generally + looks like this: + + +options = { + name = mkOption { + type = type specification; + default = default value; + example = example value; + description = "Description for use in the NixOS manual."; + }; +}; + + + The attribute names within the name attribute + path must be camel cased in general but should, as an exception, + match the + + package attribute name when referencing a Nixpkgs package. + For example, the option + services.nix-serve.bindAddress references the + nix-serve Nixpkgs package. + + + The function mkOption accepts the following + arguments. + + + + + type + + + + The type of the option (see + ). It may be omitted, but + that’s not advisable since it may lead to errors that are hard + to diagnose. + + + + + + default + + + + The default value used if no value is defined by any module. A + default is not required; but if a default is not given, then + users of the module will have to define the value of the + option, otherwise an error will be thrown. + + + + + + example + + + + An example value that will be shown in the NixOS manual. + + + + + + description + + + + A textual description of the option, in DocBook format, that + will be included in the NixOS manual. + + + + +
+ Extensible Option Types + + Extensible option types is a feature that allow to extend certain + types declaration through multiple module files. This feature only + work with a restricted set of types, namely + enum and submodules and any + composed forms of them. + + + Extensible option types can be used for enum + options that affects multiple modules, or as an alternative to + related enable options. + + + As an example, we will take the case of display managers. There is + a central display manager module for generic display manager + options and a module file per display manager backend (sddm, gdm + ...). + + + There are two approach to this module structure: + + + + + Managing the display managers independently by adding an + enable option to every display manager module backend. (NixOS) + + + + + Managing the display managers in the central module by adding + an option to select which display manager backend to use. + + + + + Both approaches have problems. + + + Making backends independent can quickly become hard to manage. For + display managers, there can be only one enabled at a time, but the + type system can not enforce this restriction as there is no + relation between each backend enable option. As + a result, this restriction has to be done explicitely by adding + assertions in each display manager backend module. + + + On the other hand, managing the display managers backends in the + central module will require to change the central module option + every time a new backend is added or removed. + + + By using extensible option types, it is possible to create a + placeholder option in the central module + (Example: + Extensible type placeholder in the service module), and to + extend it in each backend module + (Example: + Extending + services.xserver.displayManager.enable in the + gdm module, + Example: + Extending + services.xserver.displayManager.enable in the + sddm module). + + + As a result, displayManager.enable option + values can be added without changing the main service module file + and the type system automatically enforce that there can only be a + single display manager enabled. + + + + Example: Extensible type placeholder in + the service module + + +services.xserver.displayManager.enable = mkOption { + description = "Display manager to use"; + type = with types; nullOr (enum [ ]); +}; + + + + Example: Extending + services.xserver.displayManager.enable in the + gdm module + + +services.xserver.displayManager.enable = mkOption { + type = with types; nullOr (enum [ "gdm" ]); +}; + + + + Example: Extending + services.xserver.displayManager.enable in the + sddm module + + +services.xserver.displayManager.enable = mkOption { + type = with types; nullOr (enum [ "sddm" ]); +}; + + + The placeholder declaration is a standard + mkOption declaration, but it is important that + extensible option declarations only use the + type argument. + + + Extensible option types work with any of the composed variants of + enum such as + with types; nullOr (enum [ "foo" "bar" ]) + or + with types; listOf (enum [ "foo" "bar" ]). + +
+
diff --git a/nixos/doc/manual/from_md/development/option-def.section.xml b/nixos/doc/manual/from_md/development/option-def.section.xml new file mode 100644 index 000000000000..8c9ef181affd --- /dev/null +++ b/nixos/doc/manual/from_md/development/option-def.section.xml @@ -0,0 +1,104 @@ +
+ Option Definitions + + Option definitions are generally straight-forward bindings of values + to option names, like + + +config = { + services.httpd.enable = true; +}; + + + However, sometimes you need to wrap an option definition or set of + option definitions in a property to achieve + certain effects: + +
+ Delaying Conditionals + + If a set of option definitions is conditional on the value of + another option, you may need to use mkIf. + Consider, for instance: + + +config = if config.services.httpd.enable then { + environment.systemPackages = [ ... ]; + ... +} else {}; + + + This definition will cause Nix to fail with an infinite + recursion error. Why? Because the value of + config.services.httpd.enable depends on the + value being constructed here. After all, you could also write the + clearly circular and contradictory: + + +config = if config.services.httpd.enable then { + services.httpd.enable = false; +} else { + services.httpd.enable = true; +}; + + + The solution is to write: + + +config = mkIf config.services.httpd.enable { + environment.systemPackages = [ ... ]; + ... +}; + + + The special function mkIf causes the evaluation + of the conditional to be pushed down into the + individual definitions, as if you had written: + + +config = { + environment.systemPackages = if config.services.httpd.enable then [ ... ] else []; + ... +}; + +
+
+ Setting Priorities + + A module can override the definitions of an option in other + modules by setting a priority. All option + definitions that do not have the lowest priority value are + discarded. By default, option definitions have priority 1000. You + can specify an explicit priority by using + mkOverride, e.g. + + +services.openssh.enable = mkOverride 10 false; + + + This definition causes all other definitions with priorities above + 10 to be discarded. The function mkForce is + equal to mkOverride 50. + +
+
+ Merging Configurations + + In conjunction with mkIf, it is sometimes + useful for a module to return multiple sets of option definitions, + to be merged together as if they were declared in separate + modules. This can be done using mkMerge: + + +config = mkMerge + [ # Unconditional stuff. + { environment.systemPackages = [ ... ]; + } + # Conditional stuff. + (mkIf config.services.bla.enable { + environment.systemPackages = [ ... ]; + }) + ]; + +
+
diff --git a/nixos/doc/manual/from_md/development/option-types.section.xml b/nixos/doc/manual/from_md/development/option-types.section.xml new file mode 100644 index 000000000000..c83ffa2add53 --- /dev/null +++ b/nixos/doc/manual/from_md/development/option-types.section.xml @@ -0,0 +1,987 @@ +
+ Options Types + + Option types are a way to put constraints on the values a module + option can take. Types are also responsible of how values are merged + in case of multiple value definitions. + +
+ Basic Types + + Basic types are the simplest available types in the module system. + Basic types include multiple string types that mainly differ in + how definition merging is handled. + + + + + types.bool + + + + A boolean, its values can be true or + false. + + + + + + types.path + + + + A filesystem path, defined as anything that when coerced to + a string starts with a slash. Even if derivations can be + considered as path, the more specific + types.package should be preferred. + + + + + + types.package + + + + A derivation or a store path. + + + + + + types.anything + + + + A type that accepts any value and recursively merges + attribute sets together. This type is recommended when the + option type is unknown. + + + + Example: + types.anything Example + + + Two definitions of this type like + + +{ + str = lib.mkDefault "foo"; + pkg.hello = pkgs.hello; + fun.fun = x: x + 1; +} + + +{ + str = lib.mkIf true "bar"; + pkg.gcc = pkgs.gcc; + fun.fun = lib.mkForce (x: x + 2); +} + + + will get merged to + + +{ + str = "bar"; + pkg.gcc = pkgs.gcc; + pkg.hello = pkgs.hello; + fun.fun = x: x + 2; +} + + + + + + types.attrs + + + + A free-form attribute set. + + + + This type will be deprecated in the future because it + doesn't recurse into attribute sets, silently drops + earlier attribute definitions, and doesn't discharge + lib.mkDefault, + lib.mkIf and co. For allowing arbitrary + attribute sets, prefer + types.attrsOf types.anything instead + which doesn't have these problems. + + + + + + + Integer-related types: + + + + + types.int + + + + A signed integer. + + + + + + types.ints.{s8, s16, s32} + + + + Signed integers with a fixed length (8, 16 or 32 bits). They + go from −2^n/2 to 2^n/2−1 respectively (e.g. + −128 to 127 for 8 + bits). + + + + + + types.ints.unsigned + + + + An unsigned integer (that is >= 0). + + + + + + types.ints.{u8, u16, u32} + + + + Unsigned integers with a fixed length (8, 16 or 32 bits). + They go from 0 to 2^n−1 respectively (e.g. + 0 to 255 for 8 bits). + + + + + + types.ints.positive + + + + A positive integer (that is > 0). + + + + + + types.port + + + + A port number. This type is an alias to + types.ints.u16. + + + + + + String-related types: + + + + + types.str + + + + A string. Multiple definitions cannot be merged. + + + + + + types.lines + + + + A string. Multiple definitions are concatenated with a new + line "\n". + + + + + + types.commas + + + + A string. Multiple definitions are concatenated with a comma + ",". + + + + + + types.envVar + + + + A string. Multiple definitions are concatenated with a + collon ":". + + + + + + types.strMatching + + + + A string matching a specific regular expression. Multiple + definitions cannot be merged. The regular expression is + processed using builtins.match. + + + + +
+
+ Value Types + + Value types are types that take a value parameter. + + + + + types.enum + l + + + + One element of the list + l, e.g. + types.enum [ "left" "right" ]. + Multiple definitions cannot be merged. + + + + + + types.separatedString + sep + + + + A string with a custom separator + sep, e.g. + types.separatedString "|". + + + + + + types.ints.between + lowest highest + + + + An integer between + lowest and + highest (both + inclusive). Useful for creating types like + types.port. + + + + + + types.submodule + o + + + + A set of sub options + o. + o can be an + attribute set, a function returning an attribute set, or a + path to a file containing such a value. Submodules are used + in composed types to create modular options. This is + equivalent to + types.submoduleWith { modules = toList o; shorthandOnlyDefinesConfig = true; }. + Submodules are detailed in + Submodule. + + + + + + types.submoduleWith { + modules, + specialArgs ? {}, + shorthandOnlyDefinesConfig + ? false } + + + + Like types.submodule, but more flexible + and with better defaults. It has parameters + + + + + modules A list + of modules to use by default for this submodule type. + This gets combined with all option definitions to build + the final list of modules that will be included. + + + + Only options defined with this argument are included + in rendered documentation. + + + + + + specialArgs An + attribute set of extra arguments to be passed to the + module functions. The option + _module.args should be used instead + for most arguments since it allows overriding. + specialArgs + should only be used for arguments that can't go through + the module fixed-point, because of infinite recursion or + other problems. An example is overriding the + lib argument, because + lib itself is used to define + _module.args, which makes using + _module.args to define it impossible. + + + + + shorthandOnlyDefinesConfig + Whether definitions of this type should default to the + config section of a module (see + Example: Structure of + NixOS Modules) if it is an attribute set. + Enabling this only has a benefit when the submodule + defines an option named config or + options. In such a case it would + allow the option to be set with + the-submodule.config = "value" + instead of requiring + the-submodule.config.config = "value". + This is because only when modules + don't set the + config or options + keys, all keys are interpreted as option definitions in + the config section. Enabling this + option implicitly puts all attributes in the + config section. + + + With this option enabled, defining a + non-config section requires using a + function: + the-submodule = { ... }: { options = { ... }; }. + + + + + + +
+
+ Composed Types + + Composed types are types that take a type as parameter. + listOf int and + either int str are examples of composed types. + + + + + types.listOf + t + + + + A list of t type, + e.g. types.listOf int. Multiple + definitions are merged with list concatenation. + + + + + + types.attrsOf + t + + + + An attribute set of where all the values are of + t type. Multiple + definitions result in the joined attribute set. + + + + This type is strict in its values, + which in turn means attributes cannot depend on other + attributes. See types.lazyAttrsOf for + a lazy version. + + + + + + + types.lazyAttrsOf + t + + + + An attribute set of where all the values are of + t type. Multiple + definitions result in the joined attribute set. This is the + lazy version of types.attrsOf , allowing + attributes to depend on each other. + + + + This version does not fully support conditional + definitions! With an option foo of this + type and a definition + foo.attr = lib.mkIf false 10, + evaluating foo ? attr will return + true even though it should be false. + Accessing the value will then throw an error. For types + t that have an + emptyValue defined, that value will be + returned instead of throwing an error. So if the type of + foo.attr was + lazyAttrsOf (nullOr int), + null would be returned instead for the + same mkIf false definition. + + + + + + + types.nullOr + t + + + + null or type + t. Multiple + definitions are merged according to type + t. + + + + + + types.uniq + t + + + + Ensures that type t + cannot be merged. It is used to ensure option definitions + are declared only once. + + + + + + types.either + t1 t2 + + + + Type t1 or type + t2, e.g. + with types; either int str. Multiple + definitions cannot be merged. + + + + + + types.oneOf [ + t1 t2 ... ] + + + + Type t1 or type + t2 and so forth, + e.g. with types; oneOf [ int str bool ]. + Multiple definitions cannot be merged. + + + + + + types.coercedTo + from f to + + + + Type to or type + from which will be + coerced to type to + using function f + which takes an argument of type + from and return a + value of type to. + Can be used to preserve backwards compatibility of an option + if its type was changed. + + + + +
+
+ Submodule + + submodule is a very powerful type that defines + a set of sub-options that are handled like a separate module. + + + It takes a parameter o, + that should be a set, or a function returning a set with an + options key defining the sub-options. Submodule + option definitions are type-checked accordingly to the + options declarations. Of course, you can nest + submodule option definitons for even higher modularity. + + + The option set can be defined directly + (Example: Directly defined + submodule) or as reference + (Example: Submodule defined + as a reference). + + + + Example: Directly defined + submodule + + +options.mod = mkOption { + description = "submodule example"; + type = with types; submodule { + options = { + foo = mkOption { + type = int; + }; + bar = mkOption { + type = str; + }; + }; + }; +}; + + + + Example: Submodule defined as a + reference + + +let + modOptions = { + options = { + foo = mkOption { + type = int; + }; + bar = mkOption { + type = int; + }; + }; + }; +in +options.mod = mkOption { + description = "submodule example"; + type = with types; submodule modOptions; +}; + + + The submodule type is especially interesting + when used with composed types like attrsOf or + listOf. When composed with + listOf + (Example: + Declaration of a list of submodules), + submodule allows multiple definitions of the + submodule option set + (Example: + Definition of a list of submodules). + + + + Example: Declaration of a list of + submodules + + +options.mod = mkOption { + description = "submodule example"; + type = with types; listOf (submodule { + options = { + foo = mkOption { + type = int; + }; + bar = mkOption { + type = str; + }; + }; + }); +}; + + + + Example: Definition of a list of + submodules + + +config.mod = [ + { foo = 1; bar = "one"; } + { foo = 2; bar = "two"; } +]; + + + When composed with attrsOf + (Example: + Declaration of attribute sets of submodules), + submodule allows multiple named definitions of + the submodule option set + (Example: + Definition of attribute sets of submodules). + + + + Example: Declaration of attribute sets of + submodules + + +options.mod = mkOption { + description = "submodule example"; + type = with types; attrsOf (submodule { + options = { + foo = mkOption { + type = int; + }; + bar = mkOption { + type = str; + }; + }; + }); +}; + + + + Example: Definition of attribute sets of + submodules + + +config.mod.one = { foo = 1; bar = "one"; }; +config.mod.two = { foo = 2; bar = "two"; }; + +
+
+ Extending types + + Types are mainly characterized by their check + and merge functions. + + + + + check + + + + The function to type check the value. Takes a value as + parameter and return a boolean. It is possible to extend a + type check with the addCheck function + (Example: Adding a + type check), or to fully override the check function + (Example: + Overriding a type check). + + + + Example: Adding a type + check + + +byte = mkOption { + description = "An integer between 0 and 255."; + type = types.addCheck types.int (x: x >= 0 && x <= 255); +}; + + + + Example: Overriding a type + check + + +nixThings = mkOption { + description = "words that start with 'nix'"; + type = types.str // { + check = (x: lib.hasPrefix "nix" x) + }; +}; + + + + + + merge + + + + Function to merge the options values when multiple values + are set. The function takes two parameters, + loc the option path as a list of strings, + and defs the list of defined values as a + list. It is possible to override a type merge function for + custom needs. + + + + +
+
+ Custom Types + + Custom types can be created with the + mkOptionType function. As type creation + includes some more complex topics such as submodule handling, it + is recommended to get familiar with types.nix + code before creating a new type. + + + The only required parameter is name. + + + + + name + + + + A string representation of the type function name. + + + + + + definition + + + + Description of the type used in documentation. Give + information of the type and any of its arguments. + + + + + + check + + + + A function to type check the definition value. Takes the + definition value as a parameter and returns a boolean + indicating the type check result, true + for success and false for failure. + + + + + + merge + + + + A function to merge multiple definitions values. Takes two + parameters: + + + + + loc + + + + The option path as a list of strings, e.g. + ["boot" "loader "grub" "enable"]. + + + + + + defs + + + + The list of sets of defined value + and file where the value was + defined, e.g. + [ { file = "/foo.nix"; value = 1; } { file = "/bar.nix"; value = 2 } ]. + The merge function should return + the merged value or throw an error in case the values + are impossible or not meant to be merged. + + + + + + + + + getSubOptions + + + + For composed types that can take a submodule as type + parameter, this function generate sub-options documentation. + It takes the current option prefix as a list and return the + set of sub-options. Usually defined in a recursive manner by + adding a term to the prefix, e.g. + prefix: elemType.getSubOptions (prefix ++ ["prefix"]) + where + "prefix" + is the newly added prefix. + + + + + + getSubModules + + + + For composed types that can take a submodule as type + parameter, this function should return the type parameters + submodules. If the type parameter is called + elemType, the function should just + recursively look into submodules by returning + elemType.getSubModules;. + + + + + + substSubModules + + + + For composed types that can take a submodule as type + parameter, this function can be used to substitute the + parameter of a submodule type. It takes a module as + parameter and return the type with the submodule options + substituted. It is usually defined as a type function call + with a recursive call to substSubModules, + e.g for a type composedType that take an + elemtype type parameter, this function + should be defined as + m: composedType (elemType.substSubModules m). + + + + + + typeMerge + + + + A function to merge multiple type declarations. Takes the + type to merge functor as parameter. A + null return value means that type cannot + be merged. + + + + + f + + + + The type to merge functor. + + + + + + Note: There is a generic defaultTypeMerge + that work with most of value and composed types. + + + + + + functor + + + + An attribute set representing the type. It is used for type + operations and has the following keys: + + + + + type + + + + The type function. + + + + + + wrapped + + + + Holds the type parameter for composed types. + + + + + + payload + + + + Holds the value parameter for value types. The types + that have a payload are the + enum, + separatedString and + submodule types. + + + + + + binOp + + + + A binary operation that can merge the payloads of two + same types. Defined as a function that take two + payloads as parameters and return the payloads merged. + + + + + + + +
+
diff --git a/nixos/doc/manual/from_md/development/replace-modules.section.xml b/nixos/doc/manual/from_md/development/replace-modules.section.xml new file mode 100644 index 000000000000..cf8a39ba844f --- /dev/null +++ b/nixos/doc/manual/from_md/development/replace-modules.section.xml @@ -0,0 +1,70 @@ +
+ Replace Modules + + Modules that are imported can also be disabled. The option + declarations, config implementation and the imports of a disabled + module will be ignored, allowing another to take it's place. This + can be used to import a set of modules from another channel while + keeping the rest of the system on a stable release. + + + disabledModules is a top level attribute like + imports, options and + config. It contains a list of modules that will + be disabled. This can either be the full path to the module or a + string with the filename relative to the modules path (eg. + <nixpkgs/nixos/modules> for nixos). + + + This example will replace the existing postgresql module with the + version defined in the nixos-unstable channel while keeping the rest + of the modules and packages from the original nixos channel. This + only overrides the module definition, this won't use postgresql from + nixos-unstable unless explicitly configured to do so. + + +{ config, lib, pkgs, ... }: + +{ + disabledModules = [ "services/databases/postgresql.nix" ]; + + imports = + [ # Use postgresql service from nixos-unstable channel. + # sudo nix-channel --add https://nixos.org/channels/nixos-unstable nixos-unstable + <nixos-unstable/nixos/modules/services/databases/postgresql.nix> + ]; + + services.postgresql.enable = true; +} + + + This example shows how to define a custom module as a replacement + for an existing module. Importing this module will disable the + original module without having to know it's implementation details. + + +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.man; +in + +{ + disabledModules = [ "services/programs/man.nix" ]; + + options = { + programs.man.enable = mkOption { + type = types.bool; + default = true; + description = "Whether to enable manual pages."; + }; + }; + + config = mkIf cfg.enabled { + warnings = [ "disabled manpages for production deployments." ]; + }; +} + +
diff --git a/nixos/doc/manual/from_md/development/settings-options.section.xml b/nixos/doc/manual/from_md/development/settings-options.section.xml new file mode 100644 index 000000000000..c9430b77579c --- /dev/null +++ b/nixos/doc/manual/from_md/development/settings-options.section.xml @@ -0,0 +1,285 @@ +
+ Options for Program Settings + + Many programs have configuration files where program-specific + settings can be declared. File formats can be separated into two + categories: + + + + + Nix-representable ones: These can trivially be mapped to a + subset of Nix syntax. E.g. JSON is an example, since its values + like {"foo":{"bar":10}} + can be mapped directly to Nix: + { foo = { bar = 10; }; }. Other examples are + INI, YAML and TOML. The following section explains the + convention for these settings. + + + + + Non-nix-representable ones: These can't be trivially mapped to a + subset of Nix syntax. Most generic programming languages are in + this group, e.g. bash, since the statement + if true; then echo hi; fi doesn't have a + trivial representation in Nix. + + + Currently there are no fixed conventions for these, but it is + common to have a configFile option for + setting the configuration file path directly. The default value + of configFile can be an auto-generated file, + with convenient options for controlling the contents. For + example an option of type attrsOf str can be + used for representing environment variables which generates a + section like export FOO="foo". + Often it can also be useful to also include an + extraConfig option of type + lines to allow arbitrary text after the + autogenerated part of the file. + + + +
+ Nix-representable Formats (JSON, YAML, TOML, INI, + ...) + + By convention, formats like this are handled with a generic + settings option, representing the full program + configuration as a Nix value. The type of this option should + represent the format. The most common formats have a predefined + type and string generator already declared under + pkgs.formats: + + + + + pkgs.formats.json { } + + + + A function taking an empty attribute set (for future + extensibility) and returning a set with JSON-specific + attributes type and + generate as specified + below. + + + + + + pkgs.formats.yaml { } + + + + A function taking an empty attribute set (for future + extensibility) and returning a set with YAML-specific + attributes type and + generate as specified + below. + + + + + + pkgs.formats.ini { + listsAsDuplicateKeys ? + false, listToValue ? + null, ... } + + + + A function taking an attribute set with values + + + + + listsAsDuplicateKeys + + + + A boolean for controlling whether list values can be + used to represent duplicate INI keys + + + + + + listToValue + + + + A function for turning a list of values into a single + value. + + + + + + It returns a set with INI-specific attributes + type and generate as + specified below. + + + + + + pkgs.formats.toml { } + + + + A function taking an empty attribute set (for future + extensibility) and returning a set with TOML-specific + attributes type and + generate as specified + below. + + + + + + These functions all return an attribute set with these values: + + + + + type + + + + A module system type representing a value of the format + + + + + + generate + filename jsonValue + + + + A function that can render a value of the format to a file. + Returns a file path. + + + + This function puts the value contents in the Nix store. So + this should be avoided for secrets. + + + + + + + + Example: Module with conventional + settings option + + + The following shows a module for an example program that uses a + JSON configuration file. It demonstrates how above values can be + used, along with some other related best practices. See the + comments for explanations. + + +{ options, config, lib, pkgs, ... }: +let + cfg = config.services.foo; + # Define the settings format used for this program + settingsFormat = pkgs.formats.json {}; +in { + + options.services.foo = { + enable = lib.mkEnableOption "foo service"; + + settings = lib.mkOption { + # Setting this type allows for correct merging behavior + type = settingsFormat.type; + default = {}; + description = '' + Configuration for foo, see + <link xlink:href="https://example.com/docs/foo"/> + for supported settings. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + # We can assign some default settings here to make the service work by just + # enabling it. We use `mkDefault` for values that can be changed without + # problems + services.foo.settings = { + # Fails at runtime without any value set + log_level = lib.mkDefault "WARN"; + + # We assume systemd's `StateDirectory` is used, so we require this value, + # therefore no mkDefault + data_path = "/var/lib/foo"; + + # Since we use this to create a user we need to know the default value at + # eval time + user = lib.mkDefault "foo"; + }; + + environment.etc."foo.json".source = + # The formats generator function takes a filename and the Nix value + # representing the format value and produces a filepath with that value + # rendered in the format + settingsFormat.generate "foo-config.json" cfg.settings; + + # We know that the `user` attribute exists because we set a default value + # for it above, allowing us to use it without worries here + users.users.${cfg.settings.user} = { isSystemUser = true; }; + + # ... + }; +} + +
+ Option declarations for attributes + + Some settings attributes may deserve some + extra care. They may need a different type, default or merging + behavior, or they are essential options that should show their + documentation in the manual. This can be done using + . + + + We extend above example using freeform modules to declare an + option for the port, which will enforce it to be a valid integer + and make it show up in the manual. + + + + Example: Declaring a type-checked + settings attribute + + +settings = lib.mkOption { + type = lib.types.submodule { + + freeformType = settingsFormat.type; + + # Declare an option for the port such that the type is checked and this option + # is shown in the manual. + options.port = lib.mkOption { + type = lib.types.port; + default = 8080; + description = '' + Which port this service should listen on. + ''; + }; + + }; + default = {}; + description = '' + Configuration for Foo, see + <link xlink:href="https://example.com/docs/foo"/> + for supported values. + ''; +}; + +
+
+