Merge pull request #129136 from bobby285271/pr14
nixos/doc: convert "Chapter 58. Writing NixOS Modules" to CommonMark
This commit is contained in:
commit
c7d32059b1
79
nixos/doc/manual/development/freeform-modules.section.md
Normal file
79
nixos/doc/manual/development/freeform-modules.section.md
Normal file
@ -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.
|
||||
:::
|
@ -1,68 +0,0 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-freeform-modules">
|
||||
<title>Freeform modules</title>
|
||||
<para>
|
||||
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 <literal>attrsOf</literal> options in order to accept all attribute names.
|
||||
</para>
|
||||
<para>
|
||||
This feature can be enabled by using the attribute <literal>freeformType</literal> 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 <literal>config</literal> set. Since this feature nullifies name checking for entire option trees, it is only recommended for use in submodules.
|
||||
</para>
|
||||
<example xml:id="ex-freeform-module">
|
||||
<title>Freeform submodule</title>
|
||||
<para>
|
||||
The following shows a submodule assigning a freeform type that allows arbitrary attributes with <literal>str</literal> values below <literal>settings</literal>, but also declares an option for the <literal>settings.port</literal> attribute to have it type-checked and assign a default value. See <xref linkend="ex-settings-typed-attrs"/> for a more complete example.
|
||||
</para>
|
||||
<programlisting>
|
||||
{ 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;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
And the following shows what such a module then allows
|
||||
</para>
|
||||
<programlisting>
|
||||
{
|
||||
# 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";
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
<note>
|
||||
<para>
|
||||
Freeform attributes cannot depend on other attributes of the same set without infinite recursion:
|
||||
<programlisting>
|
||||
{
|
||||
# This throws infinite recursion encountered
|
||||
settings.logLevel = lib.mkIf (config.settings.port == 80) "debug";
|
||||
}
|
||||
</programlisting>
|
||||
To prevent this, declare options for all attributes that need to depend on others. For above example this means to declare <literal>logLevel</literal> to be an option.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
46
nixos/doc/manual/development/importing-modules.section.md
Normal file
46
nixos/doc/manual/development/importing-modules.section.md
Normal file
@ -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;
|
||||
}
|
||||
```
|
@ -1,56 +0,0 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-importing-modules">
|
||||
<title>Importing Modules</title>
|
||||
|
||||
<para>
|
||||
Sometimes NixOS modules need to be used in configuration but exist outside of
|
||||
Nixpkgs. These modules can be imported:
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ # Use a locally-available module definition in
|
||||
# ./example-module/default.nix
|
||||
./example-module
|
||||
];
|
||||
|
||||
services.exampleModule.enable = true;
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
The environment variable <literal>NIXOS_EXTRA_MODULE_PATH</literal> 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:
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
# ./module-list/default.nix
|
||||
[
|
||||
./example-module1
|
||||
./example-module2
|
||||
]
|
||||
</programlisting>
|
||||
|
||||
<programlisting>
|
||||
# ./extra-module/default.nix
|
||||
{ imports = import ./module-list.nix; }
|
||||
</programlisting>
|
||||
|
||||
<programlisting>
|
||||
# NIXOS_EXTRA_MODULE_PATH=/absolute/path/to/extra-module
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
# No `imports` needed
|
||||
|
||||
services.exampleModule1.enable = true;
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
40
nixos/doc/manual/development/meta-attributes.section.md
Normal file
40
nixos/doc/manual/development/meta-attributes.section.md
Normal file
@ -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
|
||||
```
|
@ -1,63 +0,0 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-meta-attributes">
|
||||
<title>Meta Attributes</title>
|
||||
|
||||
<para>
|
||||
Like Nix packages, NixOS modules can declare meta-attributes to provide extra
|
||||
information. Module meta attributes are defined in the
|
||||
<filename
|
||||
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/misc/meta.nix">meta.nix</filename>
|
||||
special module.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>meta</literal> is a top level attribute like
|
||||
<literal>options</literal> and <literal>config</literal>. Available
|
||||
meta-attributes are <literal>maintainers</literal> and
|
||||
<literal>doc</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Each of the meta-attributes must be defined at most once per module file.
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
options = {
|
||||
...
|
||||
};
|
||||
|
||||
config = {
|
||||
...
|
||||
};
|
||||
|
||||
meta = {
|
||||
maintainers = with lib.maintainers; [ ericsagnes ]; <co
|
||||
xml:id='modules-meta-1' />
|
||||
doc = ./default.xml; <co xml:id='modules-meta-2' />
|
||||
};
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
<calloutlist>
|
||||
<callout arearefs='modules-meta-1'>
|
||||
<para>
|
||||
<varname>maintainers</varname> contains a list of the module maintainers.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs='modules-meta-2'>
|
||||
<para>
|
||||
<varname>doc</varname> points to a valid DocBook file containing the module
|
||||
documentation. Its contents is automatically added to
|
||||
<xref
|
||||
linkend="ch-configuration"/>. Changes to a module documentation
|
||||
have to be checked to not break building the NixOS manual:
|
||||
</para>
|
||||
<screen><prompt>$ </prompt>nix-build nixos/release.nix -A manual.x86_64-linux</screen>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
</section>
|
136
nixos/doc/manual/development/option-declarations.section.md
Normal file
136
nixos/doc/manual/development/option-declarations.section.md
Normal file
@ -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" ])`.
|
@ -1,199 +0,0 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-option-declarations">
|
||||
<title>Option Declarations</title>
|
||||
|
||||
<para>
|
||||
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:
|
||||
<programlisting>
|
||||
options = {
|
||||
<replaceable>name</replaceable> = mkOption {
|
||||
type = <replaceable>type specification</replaceable>;
|
||||
default = <replaceable>default value</replaceable>;
|
||||
example = <replaceable>example value</replaceable>;
|
||||
description = "<replaceable>Description for use in the NixOS manual.</replaceable>";
|
||||
};
|
||||
};
|
||||
</programlisting>
|
||||
The attribute names within the <replaceable>name</replaceable> attribute path
|
||||
must be camel cased in general but should, as an exception, match the
|
||||
<link
|
||||
xlink:href="https://nixos.org/nixpkgs/manual/#sec-package-naming">
|
||||
package attribute name</link> when referencing a Nixpkgs package. For
|
||||
example, the option <varname>services.nix-serve.bindAddress</varname>
|
||||
references the <varname>nix-serve</varname> Nixpkgs package.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The function <varname>mkOption</varname> accepts the following arguments.
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>type</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The type of the option (see <xref linkend='sec-option-types' />). It may
|
||||
be omitted, but that’s not advisable since it may lead to errors that
|
||||
are hard to diagnose.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>default</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>example</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An example value that will be shown in the NixOS manual.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>description</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A textual description of the option, in DocBook format, that will be
|
||||
included in the NixOS manual.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
<section xml:id="sec-option-declarations-eot">
|
||||
<title>Extensible Option Types</title>
|
||||
|
||||
<para>
|
||||
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 <literal>enum</literal> and
|
||||
<literal>submodules</literal> and any composed forms of them.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Extensible option types can be used for <literal>enum</literal> options that
|
||||
affects multiple modules, or as an alternative to related
|
||||
<literal>enable</literal> options.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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 ...).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There are two approach to this module structure:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Managing the display managers independently by adding an enable option to
|
||||
every display manager module backend. (NixOS)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Managing the display managers in the central module by adding an option
|
||||
to select which display manager backend to use.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Both approaches have problems.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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
|
||||
<literal>enable</literal> option. As a result, this restriction has to be
|
||||
done explicitely by adding assertions in each display manager backend
|
||||
module.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
By using extensible option types, it is possible to create a placeholder
|
||||
option in the central module
|
||||
(<xref linkend='ex-option-declaration-eot-service'
|
||||
/>), and to extend
|
||||
it in each backend module
|
||||
(<xref
|
||||
linkend='ex-option-declaration-eot-backend-gdm' />,
|
||||
<xref
|
||||
linkend='ex-option-declaration-eot-backend-sddm' />).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As a result, <literal>displayManager.enable</literal> 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.
|
||||
</para>
|
||||
|
||||
<example xml:id='ex-option-declaration-eot-service'>
|
||||
<title>Extensible type placeholder in the service module</title>
|
||||
<screen>
|
||||
services.xserver.displayManager.enable = mkOption {
|
||||
description = "Display manager to use";
|
||||
type = with types; nullOr (enum [ ]);
|
||||
};</screen>
|
||||
</example>
|
||||
|
||||
<example xml:id='ex-option-declaration-eot-backend-gdm'>
|
||||
<title>Extending <literal>services.xserver.displayManager.enable</literal> in the <literal>gdm</literal> module</title>
|
||||
<screen>
|
||||
services.xserver.displayManager.enable = mkOption {
|
||||
type = with types; nullOr (enum [ "gdm" ]);
|
||||
};</screen>
|
||||
</example>
|
||||
|
||||
<example xml:id='ex-option-declaration-eot-backend-sddm'>
|
||||
<title>Extending <literal>services.xserver.displayManager.enable</literal> in the <literal>sddm</literal> module</title>
|
||||
<screen>
|
||||
services.xserver.displayManager.enable = mkOption {
|
||||
type = with types; nullOr (enum [ "sddm" ]);
|
||||
};</screen>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
The placeholder declaration is a standard <literal>mkOption</literal>
|
||||
declaration, but it is important that extensible option declarations only
|
||||
use the <literal>type</literal> argument.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Extensible option types work with any of the composed variants of
|
||||
<literal>enum</literal> such as <literal>with types; nullOr (enum [ "foo"
|
||||
"bar" ])</literal> or <literal>with types; listOf (enum [ "foo" "bar"
|
||||
])</literal>.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
91
nixos/doc/manual/development/option-def.section.md
Normal file
91
nixos/doc/manual/development/option-def.section.md
Normal file
@ -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 = [ ... ];
|
||||
})
|
||||
];
|
||||
```
|
@ -1,99 +0,0 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-option-definitions">
|
||||
<title>Option Definitions</title>
|
||||
|
||||
<para>
|
||||
Option definitions are generally straight-forward bindings of values to
|
||||
option names, like
|
||||
<programlisting>
|
||||
config = {
|
||||
services.httpd.enable = true;
|
||||
};
|
||||
</programlisting>
|
||||
However, sometimes you need to wrap an option definition or set of option
|
||||
definitions in a <emphasis>property</emphasis> to achieve certain effects:
|
||||
</para>
|
||||
|
||||
<simplesect xml:id="sec-option-definitions-delaying-conditionals">
|
||||
<title>Delaying Conditionals</title>
|
||||
<para>
|
||||
If a set of option definitions is conditional on the value of another
|
||||
option, you may need to use <varname>mkIf</varname>. Consider, for instance:
|
||||
<programlisting>
|
||||
config = if config.services.httpd.enable then {
|
||||
environment.systemPackages = [ <replaceable>...</replaceable> ];
|
||||
<replaceable>...</replaceable>
|
||||
} else {};
|
||||
</programlisting>
|
||||
This definition will cause Nix to fail with an “infinite recursion”
|
||||
error. Why? Because the value of
|
||||
<option>config.services.httpd.enable</option> depends on the value being
|
||||
constructed here. After all, you could also write the clearly circular and
|
||||
contradictory:
|
||||
<programlisting>
|
||||
config = if config.services.httpd.enable then {
|
||||
services.httpd.enable = false;
|
||||
} else {
|
||||
services.httpd.enable = true;
|
||||
};
|
||||
</programlisting>
|
||||
The solution is to write:
|
||||
<programlisting>
|
||||
config = mkIf config.services.httpd.enable {
|
||||
environment.systemPackages = [ <replaceable>...</replaceable> ];
|
||||
<replaceable>...</replaceable>
|
||||
};
|
||||
</programlisting>
|
||||
The special function <varname>mkIf</varname> causes the evaluation of the
|
||||
conditional to be “pushed down” into the individual definitions, as if
|
||||
you had written:
|
||||
<programlisting>
|
||||
config = {
|
||||
environment.systemPackages = if config.services.httpd.enable then [ <replaceable>...</replaceable> ] else [];
|
||||
<replaceable>...</replaceable>
|
||||
};
|
||||
</programlisting>
|
||||
</para>
|
||||
</simplesect>
|
||||
|
||||
<simplesect xml:id="sec-option-definitions-setting-priorities">
|
||||
<title>Setting Priorities</title>
|
||||
<para>
|
||||
A module can override the definitions of an option in other modules by
|
||||
setting a <emphasis>priority</emphasis>. 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
|
||||
<varname>mkOverride</varname>, e.g.
|
||||
<programlisting>
|
||||
services.openssh.enable = mkOverride 10 false;
|
||||
</programlisting>
|
||||
This definition causes all other definitions with priorities above 10 to be
|
||||
discarded. The function <varname>mkForce</varname> is equal to
|
||||
<varname>mkOverride 50</varname>.
|
||||
</para>
|
||||
</simplesect>
|
||||
|
||||
<simplesect xml:id="sec-option-definitions-merging">
|
||||
<title>Merging Configurations</title>
|
||||
<para>
|
||||
In conjunction with <literal>mkIf</literal>, 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
|
||||
<varname>mkMerge</varname>:
|
||||
<programlisting>
|
||||
config = mkMerge
|
||||
[ # Unconditional stuff.
|
||||
{ environment.systemPackages = [ <replaceable>...</replaceable> ];
|
||||
}
|
||||
# Conditional stuff.
|
||||
(mkIf config.services.bla.enable {
|
||||
environment.systemPackages = [ <replaceable>...</replaceable> ];
|
||||
})
|
||||
];
|
||||
</programlisting>
|
||||
</para>
|
||||
</simplesect>
|
||||
</section>
|
558
nixos/doc/manual/development/option-types.section.md
Normal file
558
nixos/doc/manual/development/option-types.section.md
Normal file
@ -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.
|
@ -1,914 +0,0 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-option-types">
|
||||
<title>Options Types</title>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<section xml:id="sec-option-types-basic">
|
||||
<title>Basic Types</title>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.bool</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A boolean, its values can be <literal>true</literal> or
|
||||
<literal>false</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.path</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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 <literal>types.package</literal> should be preferred.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.package</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A derivation or a store path.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.anything</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A type that accepts any value and recursively merges attribute sets together.
|
||||
This type is recommended when the option type is unknown.
|
||||
<example xml:id="ex-types-anything">
|
||||
<title><literal>types.anything</literal> Example</title>
|
||||
<para>
|
||||
Two definitions of this type like
|
||||
<programlisting>
|
||||
{
|
||||
str = lib.mkDefault "foo";
|
||||
pkg.hello = pkgs.hello;
|
||||
fun.fun = x: x + 1;
|
||||
}
|
||||
</programlisting>
|
||||
<programlisting>
|
||||
{
|
||||
str = lib.mkIf true "bar";
|
||||
pkg.gcc = pkgs.gcc;
|
||||
fun.fun = lib.mkForce (x: x + 2);
|
||||
}
|
||||
</programlisting>
|
||||
will get merged to
|
||||
<programlisting>
|
||||
{
|
||||
str = "bar";
|
||||
pkg.gcc = pkgs.gcc;
|
||||
pkg.hello = pkgs.hello;
|
||||
fun.fun = x: x + 2;
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
</example>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.attrs</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A free-form attribute set.
|
||||
<warning><para>
|
||||
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 <literal>lib.mkDefault</literal>, <literal>lib.mkIf
|
||||
</literal> and co. For allowing arbitrary attribute sets, prefer
|
||||
<literal>types.attrsOf types.anything</literal> instead which doesn't
|
||||
have these problems.
|
||||
</para></warning>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>
|
||||
Integer-related types:
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.int</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A signed integer.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.ints.{s8, s16, s32}</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Signed integers with a fixed length (8, 16 or 32 bits). They go from
|
||||
<inlineequation><mathphrase>−2<superscript>n</superscript>/2</mathphrase>
|
||||
</inlineequation> to <inlineequation>
|
||||
<mathphrase>2<superscript>n</superscript>/2−1</mathphrase>
|
||||
</inlineequation> respectively (e.g. <literal>−128</literal> to
|
||||
<literal>127</literal> for 8 bits).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.ints.unsigned</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An unsigned integer (that is >= 0).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry xml:id='types.ints.ux'>
|
||||
<term>
|
||||
<varname>types.ints.{u8, u16, u32}</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Unsigned integers with a fixed length (8, 16 or 32 bits). They go from
|
||||
<inlineequation><mathphrase>0</mathphrase></inlineequation> to
|
||||
<inlineequation>
|
||||
<mathphrase>2<superscript>n</superscript>−1</mathphrase>
|
||||
</inlineequation> respectively (e.g. <literal>0</literal> to
|
||||
<literal>255</literal> for 8 bits).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.ints.positive</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A positive integer (that is > 0).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.port</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A port number. This type is an alias to
|
||||
<link linkend='types.ints.ux'><varname>types.ints.u16</varname></link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>
|
||||
String-related types:
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.str</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string. Multiple definitions cannot be merged.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.lines</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string. Multiple definitions are concatenated with a new line
|
||||
<literal>"\n"</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.commas</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string. Multiple definitions are concatenated with a comma
|
||||
<literal>","</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.envVar</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string. Multiple definitions are concatenated with a collon
|
||||
<literal>":"</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.strMatching</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string matching a specific regular expression. Multiple definitions
|
||||
cannot be merged. The regular expression is processed using
|
||||
<literal>builtins.match</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
|
||||
<section xml:id="sec-option-types-value">
|
||||
<title>Value Types</title>
|
||||
|
||||
<para>
|
||||
Value types are types that take a value parameter.
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.enum</varname> <replaceable>l</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
One element of the list <replaceable>l</replaceable>, e.g.
|
||||
<literal>types.enum [ "left" "right" ]</literal>. Multiple definitions
|
||||
cannot be merged.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.separatedString</varname> <replaceable>sep</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string with a custom separator <replaceable>sep</replaceable>, e.g.
|
||||
<literal>types.separatedString "|"</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.ints.between</varname> <replaceable>lowest</replaceable> <replaceable>highest</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An integer between <replaceable>lowest</replaceable> and
|
||||
<replaceable>highest</replaceable> (both inclusive). Useful for creating
|
||||
types like <literal>types.port</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.submodule</varname> <replaceable>o</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A set of sub options <replaceable>o</replaceable>.
|
||||
<replaceable>o</replaceable> 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
|
||||
<literal>types.submoduleWith { modules = toList o; shorthandOnlyDefinesConfig = true; }</literal>.
|
||||
Submodules are detailed in
|
||||
<xref
|
||||
linkend='section-option-types-submodule' />.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.submoduleWith</varname> {
|
||||
<replaceable>modules</replaceable>,
|
||||
<replaceable>specialArgs</replaceable> ? {},
|
||||
<replaceable>shorthandOnlyDefinesConfig</replaceable> ? false }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Like <varname>types.submodule</varname>, but more flexible and with better defaults.
|
||||
It has parameters
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<replaceable>modules</replaceable>
|
||||
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><para>
|
||||
Only options defined with this argument are included in rendered documentation.
|
||||
</para></note>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<replaceable>specialArgs</replaceable>
|
||||
An attribute set of extra arguments to be passed to the module functions.
|
||||
The option <literal>_module.args</literal> should be used instead
|
||||
for most arguments since it allows overriding. <replaceable>specialArgs</replaceable> 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
|
||||
<varname>lib</varname> argument, because <varname>lib</varname> itself is used
|
||||
to define <literal>_module.args</literal>, which makes using
|
||||
<literal>_module.args</literal> to define it impossible.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<replaceable>shorthandOnlyDefinesConfig</replaceable>
|
||||
Whether definitions of this type should default to the <literal>config</literal>
|
||||
section of a module (see <xref linkend='ex-module-syntax'/>) if it is an attribute
|
||||
set. Enabling this only has a benefit when the submodule defines an option named
|
||||
<literal>config</literal> or <literal>options</literal>. In such a case it would
|
||||
allow the option to be set with <literal>the-submodule.config = "value"</literal>
|
||||
instead of requiring <literal>the-submodule.config.config = "value"</literal>.
|
||||
This is because only when modules <emphasis>don't</emphasis> set the
|
||||
<literal>config</literal> or <literal>options</literal> keys, all keys are interpreted
|
||||
as option definitions in the <literal>config</literal> section. Enabling this option
|
||||
implicitly puts all attributes in the <literal>config</literal> section.
|
||||
</para>
|
||||
<para>
|
||||
With this option enabled, defining a non-<literal>config</literal> section requires
|
||||
using a function: <literal>the-submodule = { ... }: { options = { ... }; }</literal>.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
|
||||
<section xml:id="sec-option-types-composed">
|
||||
<title>Composed Types</title>
|
||||
|
||||
<para>
|
||||
Composed types are types that take a type as parameter. <literal>listOf
|
||||
int</literal> and <literal>either int str</literal> are examples of composed
|
||||
types.
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.listOf</varname> <replaceable>t</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A list of <replaceable>t</replaceable> type, e.g. <literal>types.listOf
|
||||
int</literal>. Multiple definitions are merged with list concatenation.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.attrsOf</varname> <replaceable>t</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An attribute set of where all the values are of
|
||||
<replaceable>t</replaceable> type. Multiple definitions result in the
|
||||
joined attribute set.
|
||||
<note><para>
|
||||
This type is <emphasis>strict</emphasis> in its values, which in turn
|
||||
means attributes cannot depend on other attributes. See <varname>
|
||||
types.lazyAttrsOf</varname> for a lazy version.
|
||||
</para></note>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.lazyAttrsOf</varname> <replaceable>t</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An attribute set of where all the values are of
|
||||
<replaceable>t</replaceable> type. Multiple definitions result in the
|
||||
joined attribute set. This is the lazy version of <varname>types.attrsOf
|
||||
</varname>, allowing attributes to depend on each other.
|
||||
<warning><para>
|
||||
This version does not fully support conditional definitions! With an
|
||||
option <varname>foo</varname> of this type and a definition
|
||||
<literal>foo.attr = lib.mkIf false 10</literal>, evaluating
|
||||
<literal>foo ? attr</literal> will return <literal>true</literal>
|
||||
even though it should be false. Accessing the value will then throw
|
||||
an error. For types <replaceable>t</replaceable> that have an
|
||||
<literal>emptyValue</literal> defined, that value will be returned
|
||||
instead of throwing an error. So if the type of <literal>foo.attr</literal>
|
||||
was <literal>lazyAttrsOf (nullOr int)</literal>, <literal>null</literal>
|
||||
would be returned instead for the same <literal>mkIf false</literal> definition.
|
||||
</para></warning>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.nullOr</varname> <replaceable>t</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>null</literal> or type <replaceable>t</replaceable>. Multiple
|
||||
definitions are merged according to type <replaceable>t</replaceable>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.uniq</varname> <replaceable>t</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Ensures that type <replaceable>t</replaceable> cannot be merged. It is
|
||||
used to ensure option definitions are declared only once.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.either</varname> <replaceable>t1</replaceable> <replaceable>t2</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Type <replaceable>t1</replaceable> or type <replaceable>t2</replaceable>,
|
||||
e.g. <literal>with types; either int str</literal>. Multiple definitions
|
||||
cannot be merged.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.oneOf</varname> [ <replaceable>t1</replaceable> <replaceable>t2</replaceable> ... ]
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Type <replaceable>t1</replaceable> or type <replaceable>t2</replaceable> and so forth,
|
||||
e.g. <literal>with types; oneOf [ int str bool ]</literal>. Multiple definitions
|
||||
cannot be merged.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>types.coercedTo</varname> <replaceable>from</replaceable> <replaceable>f</replaceable> <replaceable>to</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Type <replaceable>to</replaceable> or type
|
||||
<replaceable>from</replaceable> which will be coerced to type
|
||||
<replaceable>to</replaceable> using function <replaceable>f</replaceable>
|
||||
which takes an argument of type <replaceable>from</replaceable> and
|
||||
return a value of type <replaceable>to</replaceable>. Can be used to
|
||||
preserve backwards compatibility of an option if its type was changed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
|
||||
<section xml:id='section-option-types-submodule'>
|
||||
<title>Submodule</title>
|
||||
|
||||
<para>
|
||||
<literal>submodule</literal> is a very powerful type that defines a set of
|
||||
sub-options that are handled like a separate module.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
It takes a parameter <replaceable>o</replaceable>, that should be a set, or
|
||||
a function returning a set with an <literal>options</literal> key defining
|
||||
the sub-options. Submodule option definitions are type-checked accordingly
|
||||
to the <literal>options</literal> declarations. Of course, you can nest
|
||||
submodule option definitons for even higher modularity.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The option set can be defined directly
|
||||
(<xref linkend='ex-submodule-direct' />) or as reference
|
||||
(<xref linkend='ex-submodule-reference' />).
|
||||
</para>
|
||||
|
||||
<example xml:id='ex-submodule-direct'>
|
||||
<title>Directly defined submodule</title>
|
||||
<screen>
|
||||
options.mod = mkOption {
|
||||
description = "submodule example";
|
||||
type = with types; submodule {
|
||||
options = {
|
||||
foo = mkOption {
|
||||
type = int;
|
||||
};
|
||||
bar = mkOption {
|
||||
type = str;
|
||||
};
|
||||
};
|
||||
};
|
||||
};</screen>
|
||||
</example>
|
||||
|
||||
<example xml:id='ex-submodule-reference'>
|
||||
<title>Submodule defined as a reference</title>
|
||||
<screen>
|
||||
let
|
||||
modOptions = {
|
||||
options = {
|
||||
foo = mkOption {
|
||||
type = int;
|
||||
};
|
||||
bar = mkOption {
|
||||
type = int;
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
options.mod = mkOption {
|
||||
description = "submodule example";
|
||||
type = with types; submodule modOptions;
|
||||
};</screen>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
The <literal>submodule</literal> type is especially interesting when used
|
||||
with composed types like <literal>attrsOf</literal> or
|
||||
<literal>listOf</literal>. When composed with <literal>listOf</literal>
|
||||
(<xref linkend='ex-submodule-listof-declaration' />),
|
||||
<literal>submodule</literal> allows multiple definitions of the submodule
|
||||
option set (<xref linkend='ex-submodule-listof-definition' />).
|
||||
</para>
|
||||
|
||||
<example xml:id='ex-submodule-listof-declaration'>
|
||||
<title>Declaration of a list of submodules</title>
|
||||
<screen>
|
||||
options.mod = mkOption {
|
||||
description = "submodule example";
|
||||
type = with types; listOf (submodule {
|
||||
options = {
|
||||
foo = mkOption {
|
||||
type = int;
|
||||
};
|
||||
bar = mkOption {
|
||||
type = str;
|
||||
};
|
||||
};
|
||||
});
|
||||
};</screen>
|
||||
</example>
|
||||
|
||||
<example xml:id='ex-submodule-listof-definition'>
|
||||
<title>Definition of a list of submodules</title>
|
||||
<screen>
|
||||
config.mod = [
|
||||
{ foo = 1; bar = "one"; }
|
||||
{ foo = 2; bar = "two"; }
|
||||
];</screen>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
When composed with <literal>attrsOf</literal>
|
||||
(<xref linkend='ex-submodule-attrsof-declaration' />),
|
||||
<literal>submodule</literal> allows multiple named definitions of the
|
||||
submodule option set (<xref linkend='ex-submodule-attrsof-definition' />).
|
||||
</para>
|
||||
|
||||
<example xml:id='ex-submodule-attrsof-declaration'>
|
||||
<title>Declaration of attribute sets of submodules</title>
|
||||
<screen>
|
||||
options.mod = mkOption {
|
||||
description = "submodule example";
|
||||
type = with types; attrsOf (submodule {
|
||||
options = {
|
||||
foo = mkOption {
|
||||
type = int;
|
||||
};
|
||||
bar = mkOption {
|
||||
type = str;
|
||||
};
|
||||
};
|
||||
});
|
||||
};</screen>
|
||||
</example>
|
||||
|
||||
<example xml:id='ex-submodule-attrsof-definition'>
|
||||
<title>Declaration of attribute sets of submodules</title>
|
||||
<screen>
|
||||
config.mod.one = { foo = 1; bar = "one"; };
|
||||
config.mod.two = { foo = 2; bar = "two"; };</screen>
|
||||
</example>
|
||||
</section>
|
||||
|
||||
<section xml:id="sec-option-types-extending">
|
||||
<title>Extending types</title>
|
||||
|
||||
<para>
|
||||
Types are mainly characterized by their <literal>check</literal> and
|
||||
<literal>merge</literal> functions.
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>check</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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
|
||||
<literal>addCheck</literal> function
|
||||
(<xref
|
||||
linkend='ex-extending-type-check-1' />), or to fully
|
||||
override the check function
|
||||
(<xref linkend='ex-extending-type-check-2' />).
|
||||
</para>
|
||||
<example xml:id='ex-extending-type-check-1'>
|
||||
<title>Adding a type check</title>
|
||||
<screen>
|
||||
byte = mkOption {
|
||||
description = "An integer between 0 and 255.";
|
||||
type = types.addCheck types.int (x: x >= 0 && x <= 255);
|
||||
};</screen>
|
||||
</example>
|
||||
<example xml:id='ex-extending-type-check-2'>
|
||||
<title>Overriding a type check</title>
|
||||
<screen>
|
||||
nixThings = mkOption {
|
||||
description = "words that start with 'nix'";
|
||||
type = types.str // {
|
||||
check = (x: lib.hasPrefix "nix" x)
|
||||
};
|
||||
};</screen>
|
||||
</example>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>merge</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Function to merge the options values when multiple values are set. The
|
||||
function takes two parameters, <literal>loc</literal> the option path as
|
||||
a list of strings, and <literal>defs</literal> the list of defined values
|
||||
as a list. It is possible to override a type merge function for custom
|
||||
needs.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
|
||||
<section xml:id="sec-option-types-custom">
|
||||
<title>Custom Types</title>
|
||||
|
||||
<para>
|
||||
Custom types can be created with the <literal>mkOptionType</literal>
|
||||
function. As type creation includes some more complex topics such as
|
||||
submodule handling, it is recommended to get familiar with
|
||||
<filename
|
||||
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/lib/types.nix">types.nix</filename>
|
||||
code before creating a new type.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The only required parameter is <literal>name</literal>.
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>name</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string representation of the type function name.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>definition</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Description of the type used in documentation. Give information of the
|
||||
type and any of its arguments.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>check</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function to type check the definition value. Takes the definition value
|
||||
as a parameter and returns a boolean indicating the type check result,
|
||||
<literal>true</literal> for success and <literal>false</literal> for
|
||||
failure.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>merge</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function to merge multiple definitions values. Takes two parameters:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<replaceable>loc</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The option path as a list of strings, e.g. <literal>["boot" "loader
|
||||
"grub" "enable"]</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<replaceable>defs</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The list of sets of defined <literal>value</literal> and
|
||||
<literal>file</literal> where the value was defined, e.g. <literal>[ {
|
||||
file = "/foo.nix"; value = 1; } { file = "/bar.nix"; value = 2 }
|
||||
]</literal>. The <literal>merge</literal> function should return the
|
||||
merged value or throw an error in case the values are impossible or
|
||||
not meant to be merged.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>getSubOptions</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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. <literal>prefix:
|
||||
elemType.getSubOptions (prefix ++
|
||||
[<replaceable>"prefix"</replaceable>])</literal> where
|
||||
<replaceable>"prefix"</replaceable> is the newly added prefix.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>getSubModules</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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 <literal>elemType</literal>, the function should just
|
||||
recursively look into submodules by returning
|
||||
<literal>elemType.getSubModules;</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>substSubModules</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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 <literal>substSubModules</literal>, e.g for a type
|
||||
<literal>composedType</literal> that take an <literal>elemtype</literal>
|
||||
type parameter, this function should be defined as <literal>m:
|
||||
composedType (elemType.substSubModules m)</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>typeMerge</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function to merge multiple type declarations. Takes the type to merge
|
||||
<literal>functor</literal> as parameter. A <literal>null</literal> return
|
||||
value means that type cannot be merged.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<replaceable>f</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The type to merge <literal>functor</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<para>
|
||||
Note: There is a generic <literal>defaultTypeMerge</literal> that work
|
||||
with most of value and composed types.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>functor</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An attribute set representing the type. It is used for type operations
|
||||
and has the following keys:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>type</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The type function.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>wrapped</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Holds the type parameter for composed types.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>payload</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Holds the value parameter for value types. The types that have a
|
||||
<literal>payload</literal> are the <literal>enum</literal>,
|
||||
<literal>separatedString</literal> and <literal>submodule</literal>
|
||||
types.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>binOp</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
</section>
|
64
nixos/doc/manual/development/replace-modules.section.md
Normal file
64
nixos/doc/manual/development/replace-modules.section.md
Normal file
@ -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. \<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.
|
||||
|
||||
```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
|
||||
<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.
|
||||
|
||||
```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." ];
|
||||
};
|
||||
}
|
||||
```
|
@ -1,79 +0,0 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-replace-modules">
|
||||
<title>Replace Modules</title>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>disabledModules</literal> is a top level attribute like
|
||||
<literal>imports</literal>, <literal>options</literal> and
|
||||
<literal>config</literal>. 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).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
{ 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;
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
{ 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." ];
|
||||
};
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
192
nixos/doc/manual/development/settings-options.section.md
Normal file
192
nixos/doc/manual/development/settings-options.section.md
Normal file
@ -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
|
||||
<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 {#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
|
||||
<link xlink:href="https://example.com/docs/foo"/>
|
||||
for supported values.
|
||||
'';
|
||||
};
|
||||
```
|
||||
:::
|
@ -1,226 +0,0 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-settings-options">
|
||||
<title>Options for Program Settings</title>
|
||||
|
||||
<para>
|
||||
Many programs have configuration files where program-specific settings can be declared. File formats can be separated into two categories:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Nix-representable ones: These can trivially be mapped to a subset of Nix syntax. E.g. JSON is an example, since its values like <literal>{"foo":{"bar":10}}</literal> can be mapped directly to Nix: <literal>{ foo = { bar = 10; }; }</literal>. Other examples are INI, YAML and TOML. The following section explains the convention for these settings.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
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 <literal>if true; then echo hi; fi</literal> doesn't have a trivial representation in Nix.
|
||||
</para>
|
||||
<para>
|
||||
Currently there are no fixed conventions for these, but it is common to have a <literal>configFile</literal> option for setting the configuration file path directly. The default value of <literal>configFile</literal> can be an auto-generated file, with convenient options for controlling the contents. For example an option of type <literal>attrsOf str</literal> can be used for representing environment variables which generates a section like <literal>export FOO="foo"</literal>. Often it can also be useful to also include an <literal>extraConfig</literal> option of type <literal>lines</literal> to allow arbitrary text after the autogenerated part of the file.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<section xml:id="sec-settings-nix-representable">
|
||||
<title>Nix-representable Formats (JSON, YAML, TOML, INI, ...)</title>
|
||||
<para>
|
||||
By convention, formats like this are handled with a generic <literal>settings</literal> 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 <literal>pkgs.formats</literal>:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>pkgs.formats.json</varname> { }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function taking an empty attribute set (for future extensibility) and returning a set with JSON-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>pkgs.formats.yaml</varname> { }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function taking an empty attribute set (for future extensibility) and returning a set with YAML-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>pkgs.formats.ini</varname> { <replaceable>listsAsDuplicateKeys</replaceable> ? false, <replaceable>listToValue</replaceable> ? null, ... }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function taking an attribute set with values
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>listsAsDuplicateKeys</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A boolean for controlling whether list values can be used to represent duplicate INI keys
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>listToValue</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function for turning a list of values into a single value.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
It returns a set with INI-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>pkgs.formats.toml</varname> { }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function taking an empty attribute set (for future extensibility) and returning a set with TOML-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</para>
|
||||
<para xml:id="pkgs-formats-result">
|
||||
These functions all return an attribute set with these values:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>type</varname>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A module system type representing a value of the format
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<varname>generate</varname> <replaceable>filename</replaceable> <replaceable>jsonValue</replaceable>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function that can render a value of the format to a file. Returns a file path.
|
||||
<note>
|
||||
<para>
|
||||
This function puts the value contents in the Nix store. So this should be avoided for secrets.
|
||||
</para>
|
||||
</note>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
<example xml:id="ex-settings-nix-representable">
|
||||
<title>Module with conventional <literal>settings</literal> option</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<programlisting>
|
||||
{ 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; };
|
||||
|
||||
# ...
|
||||
};
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
<section xml:id="sec-settings-attrs-options">
|
||||
<title>Option declarations for attributes</title>
|
||||
<para>
|
||||
Some <literal>settings</literal> 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 <xref linkend='sec-freeform-modules'/>.
|
||||
<example xml:id="ex-settings-typed-attrs">
|
||||
<title>Declaring a type-checked <literal>settings</literal> attribute</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<programlisting>
|
||||
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.
|
||||
'';
|
||||
};
|
||||
</programlisting>
|
||||
</example>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</section>
|
@ -179,13 +179,13 @@ in {
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
<xi:include href="option-declarations.xml" />
|
||||
<xi:include href="option-types.xml" />
|
||||
<xi:include href="option-def.xml" />
|
||||
<xi:include href="../from_md/development/option-declarations.section.xml" />
|
||||
<xi:include href="../from_md/development/option-types.section.xml" />
|
||||
<xi:include href="../from_md/development/option-def.section.xml" />
|
||||
<xi:include href="../from_md/development/assertions.section.xml" />
|
||||
<xi:include href="meta-attributes.xml" />
|
||||
<xi:include href="importing-modules.xml" />
|
||||
<xi:include href="replace-modules.xml" />
|
||||
<xi:include href="freeform-modules.xml" />
|
||||
<xi:include href="settings-options.xml" />
|
||||
<xi:include href="../from_md/development/meta-attributes.section.xml" />
|
||||
<xi:include href="../from_md/development/importing-modules.section.xml" />
|
||||
<xi:include href="../from_md/development/replace-modules.section.xml" />
|
||||
<xi:include href="../from_md/development/freeform-modules.section.xml" />
|
||||
<xi:include href="../from_md/development/settings-options.section.xml" />
|
||||
</chapter>
|
||||
|
@ -0,0 +1,87 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-freeform-modules">
|
||||
<title>Freeform modules</title>
|
||||
<para>
|
||||
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
|
||||
<literal>attrsOf</literal> options in order to accept all attribute
|
||||
names.
|
||||
</para>
|
||||
<para>
|
||||
This feature can be enabled by using the attribute
|
||||
<literal>freeformType</literal> 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
|
||||
<literal>config</literal> set. Since this feature nullifies name
|
||||
checking for entire option trees, it is only recommended for use in
|
||||
submodules.
|
||||
</para>
|
||||
<anchor xml:id="ex-freeform-module" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Freeform submodule</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
The following shows a submodule assigning a freeform type that
|
||||
allows arbitrary attributes with <literal>str</literal> values below
|
||||
<literal>settings</literal>, but also declares an option for the
|
||||
<literal>settings.port</literal> attribute to have it type-checked
|
||||
and assign a default value. See
|
||||
<link linkend="ex-settings-typed-attrs">Example: Declaring a
|
||||
type-checked <literal>settings</literal> attribute</link> for a more
|
||||
complete example.
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
{ 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;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
And the following shows what such a module then allows
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
{
|
||||
# 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";
|
||||
}
|
||||
</programlisting>
|
||||
<note>
|
||||
<para>
|
||||
Freeform attributes cannot depend on other attributes of the same
|
||||
set without infinite recursion:
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
{
|
||||
# This throws infinite recursion encountered
|
||||
settings.logLevel = lib.mkIf (config.settings.port == 80) "debug";
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
To prevent this, declare options for all attributes that need to
|
||||
depend on others. For above example this means to declare
|
||||
<literal>logLevel</literal> to be an option.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
@ -0,0 +1,47 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-importing-modules">
|
||||
<title>Importing Modules</title>
|
||||
<para>
|
||||
Sometimes NixOS modules need to be used in configuration but exist
|
||||
outside of Nixpkgs. These modules can be imported:
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ # Use a locally-available module definition in
|
||||
# ./example-module/default.nix
|
||||
./example-module
|
||||
];
|
||||
|
||||
services.exampleModule.enable = true;
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
The environment variable <literal>NIXOS_EXTRA_MODULE_PATH</literal>
|
||||
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:
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
# ./module-list/default.nix
|
||||
[
|
||||
./example-module1
|
||||
./example-module2
|
||||
]
|
||||
</programlisting>
|
||||
<programlisting language="bash">
|
||||
# ./extra-module/default.nix
|
||||
{ imports = import ./module-list.nix; }
|
||||
</programlisting>
|
||||
<programlisting language="bash">
|
||||
# NIXOS_EXTRA_MODULE_PATH=/absolute/path/to/extra-module
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
# No `imports` needed
|
||||
|
||||
services.exampleModule1.enable = true;
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
@ -0,0 +1,55 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-meta-attributes">
|
||||
<title>Meta Attributes</title>
|
||||
<para>
|
||||
Like Nix packages, NixOS modules can declare meta-attributes to
|
||||
provide extra information. Module meta attributes are defined in the
|
||||
<literal>meta.nix</literal> special module.
|
||||
</para>
|
||||
<para>
|
||||
<literal>meta</literal> is a top level attribute like
|
||||
<literal>options</literal> and <literal>config</literal>. Available
|
||||
meta-attributes are <literal>maintainers</literal> and
|
||||
<literal>doc</literal>.
|
||||
</para>
|
||||
<para>
|
||||
Each of the meta-attributes must be defined at most once per module
|
||||
file.
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
options = {
|
||||
...
|
||||
};
|
||||
|
||||
config = {
|
||||
...
|
||||
};
|
||||
|
||||
meta = {
|
||||
maintainers = with lib.maintainers; [ ericsagnes ];
|
||||
doc = ./default.xml;
|
||||
};
|
||||
}
|
||||
</programlisting>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>maintainers</literal> contains a list of the module
|
||||
maintainers.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>doc</literal> points to a valid DocBook file containing
|
||||
the module documentation. Its contents is automatically added to
|
||||
<xref linkend="ch-configuration" />. Changes to a module
|
||||
documentation have to be checked to not break building the NixOS
|
||||
manual:
|
||||
</para>
|
||||
<programlisting>
|
||||
$ nix-build nixos/release.nix -A manual.x86_64-linux
|
||||
</programlisting>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
@ -0,0 +1,203 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-option-declarations">
|
||||
<title>Option Declarations</title>
|
||||
<para>
|
||||
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:
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = type specification;
|
||||
default = default value;
|
||||
example = example value;
|
||||
description = "Description for use in the NixOS manual.";
|
||||
};
|
||||
};
|
||||
</programlisting>
|
||||
<para>
|
||||
The attribute names within the <literal>name</literal> attribute
|
||||
path must be camel cased in general but should, as an exception,
|
||||
match the
|
||||
<link xlink:href="https://nixos.org/nixpkgs/manual/#sec-package-naming">
|
||||
package attribute name</link> when referencing a Nixpkgs package.
|
||||
For example, the option
|
||||
<literal>services.nix-serve.bindAddress</literal> references the
|
||||
<literal>nix-serve</literal> Nixpkgs package.
|
||||
</para>
|
||||
<para>
|
||||
The function <literal>mkOption</literal> accepts the following
|
||||
arguments.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>type</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The type of the option (see
|
||||
<xref linkend="sec-option-types" />). It may be omitted, but
|
||||
that’s not advisable since it may lead to errors that are hard
|
||||
to diagnose.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>default</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>example</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An example value that will be shown in the NixOS manual.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>description</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A textual description of the option, in DocBook format, that
|
||||
will be included in the NixOS manual.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<section xml:id="sec-option-declarations-eot">
|
||||
<title>Extensible Option Types</title>
|
||||
<para>
|
||||
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
|
||||
<literal>enum</literal> and <literal>submodules</literal> and any
|
||||
composed forms of them.
|
||||
</para>
|
||||
<para>
|
||||
Extensible option types can be used for <literal>enum</literal>
|
||||
options that affects multiple modules, or as an alternative to
|
||||
related <literal>enable</literal> options.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
...).
|
||||
</para>
|
||||
<para>
|
||||
There are two approach to this module structure:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Managing the display managers independently by adding an
|
||||
enable option to every display manager module backend. (NixOS)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Managing the display managers in the central module by adding
|
||||
an option to select which display manager backend to use.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Both approaches have problems.
|
||||
</para>
|
||||
<para>
|
||||
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 <literal>enable</literal> option. As
|
||||
a result, this restriction has to be done explicitely by adding
|
||||
assertions in each display manager backend module.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
By using extensible option types, it is possible to create a
|
||||
placeholder option in the central module
|
||||
(<link linkend="ex-option-declaration-eot-service">Example:
|
||||
Extensible type placeholder in the service module</link>), and to
|
||||
extend it in each backend module
|
||||
(<link linkend="ex-option-declaration-eot-backend-gdm">Example:
|
||||
Extending
|
||||
<literal>services.xserver.displayManager.enable</literal> in the
|
||||
<literal>gdm</literal> module</link>,
|
||||
<link linkend="ex-option-declaration-eot-backend-sddm">Example:
|
||||
Extending
|
||||
<literal>services.xserver.displayManager.enable</literal> in the
|
||||
<literal>sddm</literal> module</link>).
|
||||
</para>
|
||||
<para>
|
||||
As a result, <literal>displayManager.enable</literal> 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.
|
||||
</para>
|
||||
<anchor xml:id="ex-option-declaration-eot-service" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Extensible type placeholder in
|
||||
the service module</emphasis>
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
services.xserver.displayManager.enable = mkOption {
|
||||
description = "Display manager to use";
|
||||
type = with types; nullOr (enum [ ]);
|
||||
};
|
||||
</programlisting>
|
||||
<anchor xml:id="ex-option-declaration-eot-backend-gdm" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Extending
|
||||
<literal>services.xserver.displayManager.enable</literal> in the
|
||||
<literal>gdm</literal> module</emphasis>
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
services.xserver.displayManager.enable = mkOption {
|
||||
type = with types; nullOr (enum [ "gdm" ]);
|
||||
};
|
||||
</programlisting>
|
||||
<anchor xml:id="ex-option-declaration-eot-backend-sddm" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Extending
|
||||
<literal>services.xserver.displayManager.enable</literal> in the
|
||||
<literal>sddm</literal> module</emphasis>
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
services.xserver.displayManager.enable = mkOption {
|
||||
type = with types; nullOr (enum [ "sddm" ]);
|
||||
};
|
||||
</programlisting>
|
||||
<para>
|
||||
The placeholder declaration is a standard
|
||||
<literal>mkOption</literal> declaration, but it is important that
|
||||
extensible option declarations only use the
|
||||
<literal>type</literal> argument.
|
||||
</para>
|
||||
<para>
|
||||
Extensible option types work with any of the composed variants of
|
||||
<literal>enum</literal> such as
|
||||
<literal>with types; nullOr (enum [ "foo" "bar" ])</literal>
|
||||
or
|
||||
<literal>with types; listOf (enum [ "foo" "bar" ])</literal>.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
104
nixos/doc/manual/from_md/development/option-def.section.xml
Normal file
104
nixos/doc/manual/from_md/development/option-def.section.xml
Normal file
@ -0,0 +1,104 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-option-definitions">
|
||||
<title>Option Definitions</title>
|
||||
<para>
|
||||
Option definitions are generally straight-forward bindings of values
|
||||
to option names, like
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
config = {
|
||||
services.httpd.enable = true;
|
||||
};
|
||||
</programlisting>
|
||||
<para>
|
||||
However, sometimes you need to wrap an option definition or set of
|
||||
option definitions in a <emphasis>property</emphasis> to achieve
|
||||
certain effects:
|
||||
</para>
|
||||
<section xml:id="sec-option-definitions-delaying-conditionals">
|
||||
<title>Delaying Conditionals</title>
|
||||
<para>
|
||||
If a set of option definitions is conditional on the value of
|
||||
another option, you may need to use <literal>mkIf</literal>.
|
||||
Consider, for instance:
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
config = if config.services.httpd.enable then {
|
||||
environment.systemPackages = [ ... ];
|
||||
...
|
||||
} else {};
|
||||
</programlisting>
|
||||
<para>
|
||||
This definition will cause Nix to fail with an <quote>infinite
|
||||
recursion</quote> error. Why? Because the value of
|
||||
<literal>config.services.httpd.enable</literal> depends on the
|
||||
value being constructed here. After all, you could also write the
|
||||
clearly circular and contradictory:
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
config = if config.services.httpd.enable then {
|
||||
services.httpd.enable = false;
|
||||
} else {
|
||||
services.httpd.enable = true;
|
||||
};
|
||||
</programlisting>
|
||||
<para>
|
||||
The solution is to write:
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
config = mkIf config.services.httpd.enable {
|
||||
environment.systemPackages = [ ... ];
|
||||
...
|
||||
};
|
||||
</programlisting>
|
||||
<para>
|
||||
The special function <literal>mkIf</literal> causes the evaluation
|
||||
of the conditional to be <quote>pushed down</quote> into the
|
||||
individual definitions, as if you had written:
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
config = {
|
||||
environment.systemPackages = if config.services.httpd.enable then [ ... ] else [];
|
||||
...
|
||||
};
|
||||
</programlisting>
|
||||
</section>
|
||||
<section xml:id="sec-option-definitions-setting-priorities">
|
||||
<title>Setting Priorities</title>
|
||||
<para>
|
||||
A module can override the definitions of an option in other
|
||||
modules by setting a <emphasis>priority</emphasis>. 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
|
||||
<literal>mkOverride</literal>, e.g.
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
services.openssh.enable = mkOverride 10 false;
|
||||
</programlisting>
|
||||
<para>
|
||||
This definition causes all other definitions with priorities above
|
||||
10 to be discarded. The function <literal>mkForce</literal> is
|
||||
equal to <literal>mkOverride 50</literal>.
|
||||
</para>
|
||||
</section>
|
||||
<section xml:id="sec-option-definitions-merging">
|
||||
<title>Merging Configurations</title>
|
||||
<para>
|
||||
In conjunction with <literal>mkIf</literal>, 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 <literal>mkMerge</literal>:
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
config = mkMerge
|
||||
[ # Unconditional stuff.
|
||||
{ environment.systemPackages = [ ... ];
|
||||
}
|
||||
# Conditional stuff.
|
||||
(mkIf config.services.bla.enable {
|
||||
environment.systemPackages = [ ... ];
|
||||
})
|
||||
];
|
||||
</programlisting>
|
||||
</section>
|
||||
</section>
|
987
nixos/doc/manual/from_md/development/option-types.section.xml
Normal file
987
nixos/doc/manual/from_md/development/option-types.section.xml
Normal file
@ -0,0 +1,987 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-option-types">
|
||||
<title>Options Types</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<section xml:id="sec-option-types-basic">
|
||||
<title>Basic Types</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.bool</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A boolean, its values can be <literal>true</literal> or
|
||||
<literal>false</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.path</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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
|
||||
<literal>types.package</literal> should be preferred.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.package</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A derivation or a store path.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.anything</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A type that accepts any value and recursively merges
|
||||
attribute sets together. This type is recommended when the
|
||||
option type is unknown.
|
||||
</para>
|
||||
<anchor xml:id="ex-types-anything" />
|
||||
<para>
|
||||
<emphasis role="strong">Example:
|
||||
<literal>types.anything</literal> Example</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
Two definitions of this type like
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
{
|
||||
str = lib.mkDefault "foo";
|
||||
pkg.hello = pkgs.hello;
|
||||
fun.fun = x: x + 1;
|
||||
}
|
||||
</programlisting>
|
||||
<programlisting language="bash">
|
||||
{
|
||||
str = lib.mkIf true "bar";
|
||||
pkg.gcc = pkgs.gcc;
|
||||
fun.fun = lib.mkForce (x: x + 2);
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
will get merged to
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
{
|
||||
str = "bar";
|
||||
pkg.gcc = pkgs.gcc;
|
||||
pkg.hello = pkgs.hello;
|
||||
fun.fun = x: x + 2;
|
||||
}
|
||||
</programlisting>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.attrs</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A free-form attribute set.
|
||||
</para>
|
||||
<warning>
|
||||
<para>
|
||||
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
|
||||
<literal>lib.mkDefault</literal>,
|
||||
<literal>lib.mkIf</literal> and co. For allowing arbitrary
|
||||
attribute sets, prefer
|
||||
<literal>types.attrsOf types.anything</literal> instead
|
||||
which doesn't have these problems.
|
||||
</para>
|
||||
</warning>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<para>
|
||||
Integer-related types:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.int</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A signed integer.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.ints.{s8, s16, s32}</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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.
|
||||
<literal>−128</literal> to <literal>127</literal> for 8
|
||||
bits).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.ints.unsigned</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An unsigned integer (that is >= 0).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.ints.{u8, u16, u32}</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Unsigned integers with a fixed length (8, 16 or 32 bits).
|
||||
They go from 0 to 2^n−1 respectively (e.g.
|
||||
<literal>0</literal> to <literal>255</literal> for 8 bits).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.ints.positive</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A positive integer (that is > 0).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.port</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A port number. This type is an alias to
|
||||
<literal>types.ints.u16</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<para>
|
||||
String-related types:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.str</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string. Multiple definitions cannot be merged.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.lines</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string. Multiple definitions are concatenated with a new
|
||||
line <literal>"\n"</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.commas</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string. Multiple definitions are concatenated with a comma
|
||||
<literal>","</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.envVar</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string. Multiple definitions are concatenated with a
|
||||
collon <literal>":"</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.strMatching</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string matching a specific regular expression. Multiple
|
||||
definitions cannot be merged. The regular expression is
|
||||
processed using <literal>builtins.match</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
<section xml:id="sec-option-types-value">
|
||||
<title>Value Types</title>
|
||||
<para>
|
||||
Value types are types that take a value parameter.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.enum</literal>
|
||||
<emphasis><literal>l</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
One element of the list
|
||||
<emphasis><literal>l</literal></emphasis>, e.g.
|
||||
<literal>types.enum [ "left" "right" ]</literal>.
|
||||
Multiple definitions cannot be merged.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.separatedString</literal>
|
||||
<emphasis><literal>sep</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string with a custom separator
|
||||
<emphasis><literal>sep</literal></emphasis>, e.g.
|
||||
<literal>types.separatedString "|"</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.ints.between</literal>
|
||||
<emphasis><literal>lowest highest</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An integer between
|
||||
<emphasis><literal>lowest</literal></emphasis> and
|
||||
<emphasis><literal>highest</literal></emphasis> (both
|
||||
inclusive). Useful for creating types like
|
||||
<literal>types.port</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.submodule</literal>
|
||||
<emphasis><literal>o</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A set of sub options
|
||||
<emphasis><literal>o</literal></emphasis>.
|
||||
<emphasis><literal>o</literal></emphasis> 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
|
||||
<literal>types.submoduleWith { modules = toList o; shorthandOnlyDefinesConfig = true; }</literal>.
|
||||
Submodules are detailed in
|
||||
<link linkend="section-option-types-submodule">Submodule</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.submoduleWith</literal> {
|
||||
<emphasis><literal>modules</literal></emphasis>,
|
||||
<emphasis><literal>specialArgs</literal></emphasis> ? {},
|
||||
<emphasis><literal>shorthandOnlyDefinesConfig</literal></emphasis>
|
||||
? false }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Like <literal>types.submodule</literal>, but more flexible
|
||||
and with better defaults. It has parameters
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis><literal>modules</literal></emphasis> 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.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
Only options defined with this argument are included
|
||||
in rendered documentation.
|
||||
</para>
|
||||
</note>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis><literal>specialArgs</literal></emphasis> An
|
||||
attribute set of extra arguments to be passed to the
|
||||
module functions. The option
|
||||
<literal>_module.args</literal> should be used instead
|
||||
for most arguments since it allows overriding.
|
||||
<emphasis><literal>specialArgs</literal></emphasis>
|
||||
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
|
||||
<literal>lib</literal> argument, because
|
||||
<literal>lib</literal> itself is used to define
|
||||
<literal>_module.args</literal>, which makes using
|
||||
<literal>_module.args</literal> to define it impossible.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis><literal>shorthandOnlyDefinesConfig</literal></emphasis>
|
||||
Whether definitions of this type should default to the
|
||||
<literal>config</literal> section of a module (see
|
||||
<link linkend="ex-module-syntax">Example: Structure of
|
||||
NixOS Modules</link>) if it is an attribute set.
|
||||
Enabling this only has a benefit when the submodule
|
||||
defines an option named <literal>config</literal> or
|
||||
<literal>options</literal>. In such a case it would
|
||||
allow the option to be set with
|
||||
<literal>the-submodule.config = "value"</literal>
|
||||
instead of requiring
|
||||
<literal>the-submodule.config.config = "value"</literal>.
|
||||
This is because only when modules
|
||||
<emphasis>don't</emphasis> set the
|
||||
<literal>config</literal> or <literal>options</literal>
|
||||
keys, all keys are interpreted as option definitions in
|
||||
the <literal>config</literal> section. Enabling this
|
||||
option implicitly puts all attributes in the
|
||||
<literal>config</literal> section.
|
||||
</para>
|
||||
<para>
|
||||
With this option enabled, defining a
|
||||
non-<literal>config</literal> section requires using a
|
||||
function:
|
||||
<literal>the-submodule = { ... }: { options = { ... }; }</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
<section xml:id="sec-option-types-composed">
|
||||
<title>Composed Types</title>
|
||||
<para>
|
||||
Composed types are types that take a type as parameter.
|
||||
<literal>listOf int</literal> and
|
||||
<literal>either int str</literal> are examples of composed types.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.listOf</literal>
|
||||
<emphasis><literal>t</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A list of <emphasis><literal>t</literal></emphasis> type,
|
||||
e.g. <literal>types.listOf int</literal>. Multiple
|
||||
definitions are merged with list concatenation.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.attrsOf</literal>
|
||||
<emphasis><literal>t</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An attribute set of where all the values are of
|
||||
<emphasis><literal>t</literal></emphasis> type. Multiple
|
||||
definitions result in the joined attribute set.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
This type is <emphasis>strict</emphasis> in its values,
|
||||
which in turn means attributes cannot depend on other
|
||||
attributes. See <literal> types.lazyAttrsOf</literal> for
|
||||
a lazy version.
|
||||
</para>
|
||||
</note>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.lazyAttrsOf</literal>
|
||||
<emphasis><literal>t</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An attribute set of where all the values are of
|
||||
<emphasis><literal>t</literal></emphasis> type. Multiple
|
||||
definitions result in the joined attribute set. This is the
|
||||
lazy version of <literal>types.attrsOf </literal>, allowing
|
||||
attributes to depend on each other.
|
||||
</para>
|
||||
<warning>
|
||||
<para>
|
||||
This version does not fully support conditional
|
||||
definitions! With an option <literal>foo</literal> of this
|
||||
type and a definition
|
||||
<literal>foo.attr = lib.mkIf false 10</literal>,
|
||||
evaluating <literal>foo ? attr</literal> will return
|
||||
<literal>true</literal> even though it should be false.
|
||||
Accessing the value will then throw an error. For types
|
||||
<emphasis><literal>t</literal></emphasis> that have an
|
||||
<literal>emptyValue</literal> defined, that value will be
|
||||
returned instead of throwing an error. So if the type of
|
||||
<literal>foo.attr</literal> was
|
||||
<literal>lazyAttrsOf (nullOr int)</literal>,
|
||||
<literal>null</literal> would be returned instead for the
|
||||
same <literal>mkIf false</literal> definition.
|
||||
</para>
|
||||
</warning>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.nullOr</literal>
|
||||
<emphasis><literal>t</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>null</literal> or type
|
||||
<emphasis><literal>t</literal></emphasis>. Multiple
|
||||
definitions are merged according to type
|
||||
<emphasis><literal>t</literal></emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.uniq</literal>
|
||||
<emphasis><literal>t</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Ensures that type <emphasis><literal>t</literal></emphasis>
|
||||
cannot be merged. It is used to ensure option definitions
|
||||
are declared only once.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.either</literal>
|
||||
<emphasis><literal>t1 t2</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Type <emphasis><literal>t1</literal></emphasis> or type
|
||||
<emphasis><literal>t2</literal></emphasis>, e.g.
|
||||
<literal>with types; either int str</literal>. Multiple
|
||||
definitions cannot be merged.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.oneOf</literal> [
|
||||
<emphasis><literal>t1 t2</literal></emphasis> ... ]
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Type <emphasis><literal>t1</literal></emphasis> or type
|
||||
<emphasis><literal>t2</literal></emphasis> and so forth,
|
||||
e.g. <literal>with types; oneOf [ int str bool ]</literal>.
|
||||
Multiple definitions cannot be merged.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>types.coercedTo</literal>
|
||||
<emphasis><literal>from f to</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Type <emphasis><literal>to</literal></emphasis> or type
|
||||
<emphasis><literal>from</literal></emphasis> which will be
|
||||
coerced to type <emphasis><literal>to</literal></emphasis>
|
||||
using function <emphasis><literal>f</literal></emphasis>
|
||||
which takes an argument of type
|
||||
<emphasis><literal>from</literal></emphasis> and return a
|
||||
value of type <emphasis><literal>to</literal></emphasis>.
|
||||
Can be used to preserve backwards compatibility of an option
|
||||
if its type was changed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
<section xml:id="section-option-types-submodule">
|
||||
<title>Submodule</title>
|
||||
<para>
|
||||
<literal>submodule</literal> is a very powerful type that defines
|
||||
a set of sub-options that are handled like a separate module.
|
||||
</para>
|
||||
<para>
|
||||
It takes a parameter <emphasis><literal>o</literal></emphasis>,
|
||||
that should be a set, or a function returning a set with an
|
||||
<literal>options</literal> key defining the sub-options. Submodule
|
||||
option definitions are type-checked accordingly to the
|
||||
<literal>options</literal> declarations. Of course, you can nest
|
||||
submodule option definitons for even higher modularity.
|
||||
</para>
|
||||
<para>
|
||||
The option set can be defined directly
|
||||
(<link linkend="ex-submodule-direct">Example: Directly defined
|
||||
submodule</link>) or as reference
|
||||
(<link linkend="ex-submodule-reference">Example: Submodule defined
|
||||
as a reference</link>).
|
||||
</para>
|
||||
<anchor xml:id="ex-submodule-direct" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Directly defined
|
||||
submodule</emphasis>
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
options.mod = mkOption {
|
||||
description = "submodule example";
|
||||
type = with types; submodule {
|
||||
options = {
|
||||
foo = mkOption {
|
||||
type = int;
|
||||
};
|
||||
bar = mkOption {
|
||||
type = str;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
</programlisting>
|
||||
<anchor xml:id="ex-submodule-reference" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Submodule defined as a
|
||||
reference</emphasis>
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
let
|
||||
modOptions = {
|
||||
options = {
|
||||
foo = mkOption {
|
||||
type = int;
|
||||
};
|
||||
bar = mkOption {
|
||||
type = int;
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
options.mod = mkOption {
|
||||
description = "submodule example";
|
||||
type = with types; submodule modOptions;
|
||||
};
|
||||
</programlisting>
|
||||
<para>
|
||||
The <literal>submodule</literal> type is especially interesting
|
||||
when used with composed types like <literal>attrsOf</literal> or
|
||||
<literal>listOf</literal>. When composed with
|
||||
<literal>listOf</literal>
|
||||
(<link linkend="ex-submodule-listof-declaration">Example:
|
||||
Declaration of a list of submodules</link>),
|
||||
<literal>submodule</literal> allows multiple definitions of the
|
||||
submodule option set
|
||||
(<link linkend="ex-submodule-listof-definition">Example:
|
||||
Definition of a list of submodules</link>).
|
||||
</para>
|
||||
<anchor xml:id="ex-submodule-listof-declaration" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Declaration of a list of
|
||||
submodules</emphasis>
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
options.mod = mkOption {
|
||||
description = "submodule example";
|
||||
type = with types; listOf (submodule {
|
||||
options = {
|
||||
foo = mkOption {
|
||||
type = int;
|
||||
};
|
||||
bar = mkOption {
|
||||
type = str;
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
</programlisting>
|
||||
<anchor xml:id="ex-submodule-listof-definition" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Definition of a list of
|
||||
submodules</emphasis>
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
config.mod = [
|
||||
{ foo = 1; bar = "one"; }
|
||||
{ foo = 2; bar = "two"; }
|
||||
];
|
||||
</programlisting>
|
||||
<para>
|
||||
When composed with <literal>attrsOf</literal>
|
||||
(<link linkend="ex-submodule-attrsof-declaration">Example:
|
||||
Declaration of attribute sets of submodules</link>),
|
||||
<literal>submodule</literal> allows multiple named definitions of
|
||||
the submodule option set
|
||||
(<link linkend="ex-submodule-attrsof-definition">Example:
|
||||
Definition of attribute sets of submodules</link>).
|
||||
</para>
|
||||
<anchor xml:id="ex-submodule-attrsof-declaration" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Declaration of attribute sets of
|
||||
submodules</emphasis>
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
options.mod = mkOption {
|
||||
description = "submodule example";
|
||||
type = with types; attrsOf (submodule {
|
||||
options = {
|
||||
foo = mkOption {
|
||||
type = int;
|
||||
};
|
||||
bar = mkOption {
|
||||
type = str;
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
</programlisting>
|
||||
<anchor xml:id="ex-submodule-attrsof-definition" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Definition of attribute sets of
|
||||
submodules</emphasis>
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
config.mod.one = { foo = 1; bar = "one"; };
|
||||
config.mod.two = { foo = 2; bar = "two"; };
|
||||
</programlisting>
|
||||
</section>
|
||||
<section xml:id="sec-option-types-extending">
|
||||
<title>Extending types</title>
|
||||
<para>
|
||||
Types are mainly characterized by their <literal>check</literal>
|
||||
and <literal>merge</literal> functions.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>check</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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 <literal>addCheck</literal> function
|
||||
(<link linkend="ex-extending-type-check-1">Example: Adding a
|
||||
type check</link>), or to fully override the check function
|
||||
(<link linkend="ex-extending-type-check-2">Example:
|
||||
Overriding a type check</link>).
|
||||
</para>
|
||||
<anchor xml:id="ex-extending-type-check-1" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Adding a type
|
||||
check</emphasis>
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
byte = mkOption {
|
||||
description = "An integer between 0 and 255.";
|
||||
type = types.addCheck types.int (x: x >= 0 && x <= 255);
|
||||
};
|
||||
</programlisting>
|
||||
<anchor xml:id="ex-extending-type-check-2" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Overriding a type
|
||||
check</emphasis>
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
nixThings = mkOption {
|
||||
description = "words that start with 'nix'";
|
||||
type = types.str // {
|
||||
check = (x: lib.hasPrefix "nix" x)
|
||||
};
|
||||
};
|
||||
</programlisting>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>merge</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Function to merge the options values when multiple values
|
||||
are set. The function takes two parameters,
|
||||
<literal>loc</literal> the option path as a list of strings,
|
||||
and <literal>defs</literal> the list of defined values as a
|
||||
list. It is possible to override a type merge function for
|
||||
custom needs.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
<section xml:id="sec-option-types-custom">
|
||||
<title>Custom Types</title>
|
||||
<para>
|
||||
Custom types can be created with the
|
||||
<literal>mkOptionType</literal> function. As type creation
|
||||
includes some more complex topics such as submodule handling, it
|
||||
is recommended to get familiar with <literal>types.nix</literal>
|
||||
code before creating a new type.
|
||||
</para>
|
||||
<para>
|
||||
The only required parameter is <literal>name</literal>.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>name</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A string representation of the type function name.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>definition</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Description of the type used in documentation. Give
|
||||
information of the type and any of its arguments.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>check</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function to type check the definition value. Takes the
|
||||
definition value as a parameter and returns a boolean
|
||||
indicating the type check result, <literal>true</literal>
|
||||
for success and <literal>false</literal> for failure.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>merge</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function to merge multiple definitions values. Takes two
|
||||
parameters:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<emphasis><literal>loc</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The option path as a list of strings, e.g.
|
||||
<literal>["boot" "loader "grub" "enable"]</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<emphasis><literal>defs</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The list of sets of defined <literal>value</literal>
|
||||
and <literal>file</literal> where the value was
|
||||
defined, e.g.
|
||||
<literal>[ { file = "/foo.nix"; value = 1; } { file = "/bar.nix"; value = 2 } ]</literal>.
|
||||
The <literal>merge</literal> function should return
|
||||
the merged value or throw an error in case the values
|
||||
are impossible or not meant to be merged.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>getSubOptions</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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.
|
||||
<literal>prefix: elemType.getSubOptions (prefix ++ ["prefix"])</literal>
|
||||
where
|
||||
<emphasis><literal>"prefix"</literal></emphasis>
|
||||
is the newly added prefix.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>getSubModules</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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
|
||||
<literal>elemType</literal>, the function should just
|
||||
recursively look into submodules by returning
|
||||
<literal>elemType.getSubModules;</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>substSubModules</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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 <literal>substSubModules</literal>,
|
||||
e.g for a type <literal>composedType</literal> that take an
|
||||
<literal>elemtype</literal> type parameter, this function
|
||||
should be defined as
|
||||
<literal>m: composedType (elemType.substSubModules m)</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>typeMerge</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function to merge multiple type declarations. Takes the
|
||||
type to merge <literal>functor</literal> as parameter. A
|
||||
<literal>null</literal> return value means that type cannot
|
||||
be merged.
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<emphasis><literal>f</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The type to merge <literal>functor</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<para>
|
||||
Note: There is a generic <literal>defaultTypeMerge</literal>
|
||||
that work with most of value and composed types.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>functor</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An attribute set representing the type. It is used for type
|
||||
operations and has the following keys:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>type</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The type function.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>wrapped</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Holds the type parameter for composed types.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>payload</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Holds the value parameter for value types. The types
|
||||
that have a <literal>payload</literal> are the
|
||||
<literal>enum</literal>,
|
||||
<literal>separatedString</literal> and
|
||||
<literal>submodule</literal> types.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>binOp</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
</section>
|
@ -0,0 +1,70 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-replace-modules">
|
||||
<title>Replace Modules</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
<literal>disabledModules</literal> is a top level attribute like
|
||||
<literal>imports</literal>, <literal>options</literal> and
|
||||
<literal>config</literal>. 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).
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
{ 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;
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
{ 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." ];
|
||||
};
|
||||
}
|
||||
</programlisting>
|
||||
</section>
|
@ -0,0 +1,285 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-settings-options">
|
||||
<title>Options for Program Settings</title>
|
||||
<para>
|
||||
Many programs have configuration files where program-specific
|
||||
settings can be declared. File formats can be separated into two
|
||||
categories:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Nix-representable ones: These can trivially be mapped to a
|
||||
subset of Nix syntax. E.g. JSON is an example, since its values
|
||||
like <literal>{"foo":{"bar":10}}</literal>
|
||||
can be mapped directly to Nix:
|
||||
<literal>{ foo = { bar = 10; }; }</literal>. Other examples are
|
||||
INI, YAML and TOML. The following section explains the
|
||||
convention for these settings.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
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
|
||||
<literal>if true; then echo hi; fi</literal> doesn't have a
|
||||
trivial representation in Nix.
|
||||
</para>
|
||||
<para>
|
||||
Currently there are no fixed conventions for these, but it is
|
||||
common to have a <literal>configFile</literal> option for
|
||||
setting the configuration file path directly. The default value
|
||||
of <literal>configFile</literal> can be an auto-generated file,
|
||||
with convenient options for controlling the contents. For
|
||||
example an option of type <literal>attrsOf str</literal> can be
|
||||
used for representing environment variables which generates a
|
||||
section like <literal>export FOO="foo"</literal>.
|
||||
Often it can also be useful to also include an
|
||||
<literal>extraConfig</literal> option of type
|
||||
<literal>lines</literal> to allow arbitrary text after the
|
||||
autogenerated part of the file.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<section xml:id="sec-settings-nix-representable">
|
||||
<title>Nix-representable Formats (JSON, YAML, TOML, INI,
|
||||
...)</title>
|
||||
<para>
|
||||
By convention, formats like this are handled with a generic
|
||||
<literal>settings</literal> 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
|
||||
<literal>pkgs.formats</literal>:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>pkgs.formats.json</literal> { }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function taking an empty attribute set (for future
|
||||
extensibility) and returning a set with JSON-specific
|
||||
attributes <literal>type</literal> and
|
||||
<literal>generate</literal> as specified
|
||||
<link linkend="pkgs-formats-result">below</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>pkgs.formats.yaml</literal> { }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function taking an empty attribute set (for future
|
||||
extensibility) and returning a set with YAML-specific
|
||||
attributes <literal>type</literal> and
|
||||
<literal>generate</literal> as specified
|
||||
<link linkend="pkgs-formats-result">below</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>pkgs.formats.ini</literal> {
|
||||
<emphasis><literal>listsAsDuplicateKeys</literal></emphasis> ?
|
||||
false, <emphasis><literal>listToValue</literal></emphasis> ?
|
||||
null, ... }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function taking an attribute set with values
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>listsAsDuplicateKeys</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A boolean for controlling whether list values can be
|
||||
used to represent duplicate INI keys
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>listToValue</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function for turning a list of values into a single
|
||||
value.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<para>
|
||||
It returns a set with INI-specific attributes
|
||||
<literal>type</literal> and <literal>generate</literal> as
|
||||
specified <link linkend="pkgs-formats-result">below</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>pkgs.formats.toml</literal> { }
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function taking an empty attribute set (for future
|
||||
extensibility) and returning a set with TOML-specific
|
||||
attributes <literal>type</literal> and
|
||||
<literal>generate</literal> as specified
|
||||
<link linkend="pkgs-formats-result">below</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<para xml:id="pkgs-formats-result">
|
||||
These functions all return an attribute set with these values:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>type</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A module system type representing a value of the format
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>generate</literal>
|
||||
<emphasis><literal>filename jsonValue</literal></emphasis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
A function that can render a value of the format to a file.
|
||||
Returns a file path.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
This function puts the value contents in the Nix store. So
|
||||
this should be avoided for secrets.
|
||||
</para>
|
||||
</note>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<anchor xml:id="ex-settings-nix-representable" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Module with conventional
|
||||
<literal>settings</literal> option</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
{ 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; };
|
||||
|
||||
# ...
|
||||
};
|
||||
}
|
||||
</programlisting>
|
||||
<section xml:id="sec-settings-attrs-options">
|
||||
<title>Option declarations for attributes</title>
|
||||
<para>
|
||||
Some <literal>settings</literal> 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
|
||||
<xref linkend="sec-freeform-modules" />.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<anchor xml:id="ex-settings-typed-attrs" />
|
||||
<para>
|
||||
<emphasis role="strong">Example: Declaring a type-checked
|
||||
<literal>settings</literal> attribute</emphasis>
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
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.
|
||||
'';
|
||||
};
|
||||
</programlisting>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
Loading…
Reference in New Issue
Block a user