nixpkgs-custom/nixos/doc/manual/development/option-types.xml

522 lines
20 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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><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>
</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>
<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>
</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><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 or a function
returning an attribute set. Submodules are used in composed types to
create modular options. Submodule are detailed in <xref
linkend='section-option-types-submodule' />.</para></listitem>
</varlistentry>
</variablelist>
</section>
<section><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.</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.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><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 = 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><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>