nixpkgs/nixos/doc/manual/development/option-types.xml
Robert Hensing 9884cb3ed0
Merge pull request #76861 from Infinisil/paths-as-submodules
lib/types: Allow paths as submodule values
2020-01-12 14:19:04 +01:00

878 lines
26 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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.attrs</varname>
</term>
<listitem>
<para>
A free-form attribute set.
</para>
</listitem>
</varlistentry>
<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>
</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>/21</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&apos;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&apos;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.loaOf</varname> <replaceable>t</replaceable>
</term>
<listitem>
<para>
An attribute set or a list of <replaceable>t</replaceable> type. Multiple
definitions are merged according to the value.
</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 &gt;= 0 &amp;&amp; x &lt;= 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>