157 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
| <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>
 | ||
| 
 | ||
| </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; in that case, if the option
 | ||
|       value is never used, 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 (slim, 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 approachs 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-slim' />, <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-slim'><title>Extending
 | ||
|     <literal>services.xserver.displayManager.enable</literal> in the
 | ||
|     <literal>slim</literal> module</title>
 | ||
| <screen>
 | ||
| services.xserver.displayManager.enable = mkOption {
 | ||
|   type = with types; nullOr (enum [ "slim" ]);
 | ||
| };</screen></example>
 | ||
| 
 | ||
| <example xml:id='ex-option-declaration-eot-backend-sddm'><title>Extending
 | ||
|     <literal>services.foo.backend</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>
 | 
