summary refs log tree commit diff
path: root/nixos/doc/manual/from_md/development/option-declarations.section.xml
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/doc/manual/from_md/development/option-declarations.section.xml')
-rw-r--r--nixos/doc/manual/from_md/development/option-declarations.section.xml327
1 files changed, 327 insertions, 0 deletions
diff --git a/nixos/doc/manual/from_md/development/option-declarations.section.xml b/nixos/doc/manual/from_md/development/option-declarations.section.xml
new file mode 100644
index 00000000000..0ac5e0eeca2
--- /dev/null
+++ b/nixos/doc/manual/from_md/development/option-declarations.section.xml
@@ -0,0 +1,327 @@
+<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 = &quot;Description for use in the NixOS manual.&quot;;
+  };
+};
+</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" />). This argument is
+          mandatory for nixpkgs modules. Setting this is highly
+          recommended for the sake of documentation and type checking.
+          In case it is not set, a fallback type with unspecified
+          behavior is used.
+        </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>defaultText</literal>
+      </term>
+      <listitem>
+        <para>
+          A textual representation of the default value to be rendered
+          verbatim in the manual. Useful if the default value is a
+          complex expression or depends on other values or packages. Use
+          <literal>lib.literalExpression</literal> for a Nix expression,
+          <literal>lib.literalDocBook</literal> for a plain English
+          description in DocBook format.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>example</literal>
+      </term>
+      <listitem>
+        <para>
+          An example value that will be shown in the NixOS manual. You
+          can use <literal>lib.literalExpression</literal> and
+          <literal>lib.literalDocBook</literal> in the same way as in
+          <literal>defaultText</literal>.
+        </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-util">
+    <title>Utility functions for common option patterns</title>
+    <section xml:id="sec-option-declarations-util-mkEnableOption">
+      <title><literal>mkEnableOption</literal></title>
+      <para>
+        Creates an Option attribute set for a boolean value option i.e
+        an option to be toggled on or off.
+      </para>
+      <para>
+        This function takes a single string argument, the name of the
+        thing to be toggled.
+      </para>
+      <para>
+        The option’s description is <quote>Whether to enable
+        &lt;name&gt;.</quote>.
+      </para>
+      <para>
+        For example:
+      </para>
+      <anchor xml:id="ex-options-declarations-util-mkEnableOption-magic" />
+      <programlisting language="bash">
+lib.mkEnableOption &quot;magic&quot;
+# is like
+lib.mkOption {
+  type = lib.types.bool;
+  default = false;
+  example = true;
+  description = &quot;Whether to enable magic.&quot;;
+}
+</programlisting>
+      <section xml:id="sec-option-declarations-util-mkPackageOption">
+        <title><literal>mkPackageOption</literal></title>
+        <para>
+          Usage:
+        </para>
+        <programlisting language="bash">
+mkPackageOption pkgs &quot;name&quot; { default = [ &quot;path&quot; &quot;in&quot; &quot;pkgs&quot; ]; example = &quot;literal example&quot;; }
+</programlisting>
+        <para>
+          Creates an Option attribute set for an option that specifies
+          the package a module should use for some purpose.
+        </para>
+        <para>
+          <emphasis role="strong">Note</emphasis>: You shouldn’t
+          necessarily make package options for all of your modules. You
+          can always overwrite a specific package throughout nixpkgs by
+          using
+          <link xlink:href="https://nixos.org/manual/nixpkgs/stable/#chap-overlays">nixpkgs
+          overlays</link>.
+        </para>
+        <para>
+          The default package is specified as a list of strings
+          representing its attribute path in nixpkgs. Because of this,
+          you need to pass nixpkgs itself as the first argument.
+        </para>
+        <para>
+          The second argument is the name of the option, used in the
+          description <quote>The &lt;name&gt; package to use.</quote>.
+          You can also pass an example value, either a literal string or
+          a package’s attribute path.
+        </para>
+        <para>
+          You can omit the default path if the name of the option is
+          also attribute path in nixpkgs.
+        </para>
+        <anchor xml:id="ex-options-declarations-util-mkPackageOption" />
+        <para>
+          Examples:
+        </para>
+        <anchor xml:id="ex-options-declarations-util-mkPackageOption-hello" />
+        <programlisting language="bash">
+lib.mkPackageOption pkgs &quot;hello&quot; { }
+# is like
+lib.mkOption {
+  type = lib.types.package;
+  default = pkgs.hello;
+  defaultText = lib.literalExpression &quot;pkgs.hello&quot;;
+  description = &quot;The hello package to use.&quot;;
+}
+</programlisting>
+        <anchor xml:id="ex-options-declarations-util-mkPackageOption-ghc" />
+        <programlisting language="bash">
+lib.mkPackageOption pkgs &quot;GHC&quot; {
+  default = [ &quot;ghc&quot; ];
+  example = &quot;pkgs.haskell.package.ghc921.ghc.withPackages (hkgs: [ hkgs.primes ])&quot;;
+}
+# is like
+lib.mkOption {
+  type = lib.types.package;
+  default = pkgs.ghc;
+  defaultText = lib.literalExpression &quot;pkgs.ghc&quot;;
+  example = lib.literalExpression &quot;pkgs.haskell.package.ghc921.ghc.withPackages (hkgs: [ hkgs.primes ])&quot;;
+  description = &quot;The GHC package to use.&quot;;
+}
+</programlisting>
+        <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 approaches we could take with this module
+            structure:
+          </para>
+          <itemizedlist>
+            <listitem>
+              <para>
+                Configuring the display managers independently by adding
+                an enable option to every display manager module
+                backend. (NixOS)
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                Configuring 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 only be one enabled
+            at a time, but the type system cannot enforce this
+            restriction as there is no relation between each backend’s
+            <literal>enable</literal> option. As a result, this
+            restriction has to be done explicitly by adding assertions
+            in each display manager backend module.
+          </para>
+          <para>
+            On the other hand, managing the display manager backends in
+            the central module will require changing 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 enforces 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 = &quot;Display manager to use&quot;;
+  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 [ &quot;gdm&quot; ]);
+};
+</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 [ &quot;sddm&quot; ]);
+};
+</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 [ &quot;foo&quot; &quot;bar&quot; ])</literal>
+            or
+            <literal>with types; listOf (enum [ &quot;foo&quot; &quot;bar&quot; ])</literal>.
+          </para>
+        </section>
+      </section>
+    </section>
+  </section>
+</section>