nixos/docs/option-declarations: Document mkEnableOption and mkPackageOption

This is a squashed commit. These are the original commit messages:

lib/option: Improve comment

better comment

Update documentation

Updated nixos/doc/manual/development/options-declarations.md with info on mkEnableOption and mkPackageOption.
Updated the comment on mkEnableOption in lib/options.nix

remove trailing whitespace

nixos/doc/option-declarations: Update IDs & formatting

nixos/docs/option-declarations: Escape angle brackets

Build DB from MD

(Amended) Fix typo
Co-authored-by: pennae <82953136+pennae@users.noreply.github.com>

(Amended) Build DB from MD (again)
This commit is contained in:
Anselm Schüler 2022-01-21 10:41:34 +01:00
parent fdf7ede344
commit c008b3d100
3 changed files with 320 additions and 118 deletions

View file

@ -100,12 +100,37 @@ rec {
type = lib.types.bool; type = lib.types.bool;
}; };
/* Creaties an Option attribute set for an option that specifies the /* Creates an Option attribute set for an option that specifies the
package a module should use. package a module should use for some purpose.
The argument default is an attribute set path in pkgs. Type: mkPackageOption :: pkgs -> string -> { default :: [string], example :: null | string | [string] } -> option
The 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.
The second argument is the name of the option, used in the description "The <name> package to use.".
You can also pass an example value, either a literal string or a package's attribute path.
You can omit the default path if the name of the option is also attribute path in nixpkgs.
Example:
mkPackageOption pkgs "hello" { }
=> { _type = "option"; default = «derivation /nix/store/3r2vg51hlxj3cx5vscp0vkv60bqxkaq0-hello-2.10.drv»; defaultText = { ... }; description = "The hello package to use."; type = { ... }; }
Example:
mkPackageOption pkgs "GHC" {
default = [ "ghc" ];
example = "pkgs.haskell.package.ghc921.ghc.withPackages (hkgs: [ hkgs.primes ])";
}
=> { _type = "option"; default = «derivation /nix/store/jxx55cxsjrf8kyh3fp2ya17q99w7541r-ghc-8.10.7.drv»; defaultText = { ... }; description = "The GHC package to use."; example = { ... }; type = { ... }; }
*/ */
mkPackageOption = pkgs: name: mkPackageOption =
# Package set (a specific version of nixpkgs)
pkgs:
# Name for the package, shown in option description
name:
{ default ? [ name ], example ? null }: { default ? [ name ], example ? null }:
let default' = if !isList default then [ default ] else default; let default' = if !isList default then [ default ] else default;
in mkOption { in mkOption {

View file

@ -57,6 +57,80 @@ The function `mkOption` accepts the following arguments.
: A textual description of the option, in DocBook format, that will be : A textual description of the option, in DocBook format, that will be
included in the NixOS manual. included in the NixOS manual.
## Utility functions for common option patterns {#sec-option-declarations-util}
### `mkEnableOption` {#sec-option-declarations-util-mkEnableOption}
Creates an Option attribute set for a boolean value option i.e an
option to be toggled on or off.
This function takes a single string argument, the name of the thing to be toggled.
The option's description is "Whether to enable \<name\>.".
For example:
::: {#ex-options-declarations-util-mkEnableOption-magic .example}
```nix
lib.mkEnableOption "magic"
# is like
lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = "Whether to enable magic.";
}
```
### `mkPackageOption` {#sec-option-declarations-util-mkPackageOption}
Usage:
```nix
mkPackageOption pkgs "name" { default = [ "path" "in" "pkgs" ]; example = "literal example"; }
```
Creates an Option attribute set for an option that specifies the package a module should use for some purpose.
**Note**: You shouldnt necessarily make package options for all of your modules. You can always overwrite a specific package throughout nixpkgs by using [nixpkgs overlays](https://nixos.org/manual/nixpkgs/stable/#chap-overlays).
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.
The second argument is the name of the option, used in the description "The \<name\> package to use.". You can also pass an example value, either a literal string or a package's attribute path.
You can omit the default path if the name of the option is also attribute path in nixpkgs.
::: {#ex-options-declarations-util-mkPackageOption .title}
Examples:
::: {#ex-options-declarations-util-mkPackageOption-hello .example}
```nix
lib.mkPackageOption pkgs "hello" { }
# is like
lib.mkOption {
type = lib.types.package;
default = pkgs.hello;
defaultText = lib.literalExpression "pkgs.hello";
description = "The hello package to use.";
}
```
::: {#ex-options-declarations-util-mkPackageOption-ghc .example}
```nix
lib.mkPackageOption pkgs "GHC" {
default = [ "ghc" ];
example = "pkgs.haskell.package.ghc921.ghc.withPackages (hkgs: [ hkgs.primes ])";
}
# is like
lib.mkOption {
type = lib.types.package;
default = pkgs.ghc;
defaultText = lib.literalExpression "pkgs.ghc";
example = lib.literalExpression "pkgs.haskell.package.ghc921.ghc.withPackages (hkgs: [ hkgs.primes ])";
description = "The GHC package to use.";
}
```
## Extensible Option Types {#sec-option-declarations-eot} ## Extensible Option Types {#sec-option-declarations-eot}
Extensible option types is a feature that allow to extend certain types Extensible option types is a feature that allow to extend certain types

View file

@ -97,25 +97,122 @@ options = {
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </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 options 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 shouldnt
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 packages 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"> <section xml:id="sec-option-declarations-eot">
<title>Extensible Option Types</title> <title>Extensible Option Types</title>
<para> <para>
Extensible option types is a feature that allow to extend certain Extensible option types is a feature that allow to extend
types declaration through multiple module files. This feature only certain types declaration through multiple module files.
work with a restricted set of types, namely This feature only work with a restricted set of types,
<literal>enum</literal> and <literal>submodules</literal> and any namely <literal>enum</literal> and
composed forms of them. <literal>submodules</literal> and any composed forms of
them.
</para> </para>
<para> <para>
Extensible option types can be used for <literal>enum</literal> Extensible option types can be used for
options that affects multiple modules, or as an alternative to <literal>enum</literal> options that affects multiple
related <literal>enable</literal> options. modules, or as an alternative to related
<literal>enable</literal> options.
</para> </para>
<para> <para>
As an example, we will take the case of display managers. There is As an example, we will take the case of display managers.
a central display manager module for generic display manager There is a central display manager module for generic
options and a module file per display manager backend (sddm, gdm display manager options and a module file per display
...). manager backend (sddm, gdm ...).
</para> </para>
<para> <para>
There are two approach to this module structure: There are two approach to this module structure:
@ -124,13 +221,15 @@ options = {
<listitem> <listitem>
<para> <para>
Managing the display managers independently by adding an Managing the display managers independently by adding an
enable option to every display manager module backend. (NixOS) enable option to every display manager module backend.
(NixOS)
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Managing the display managers in the central module by adding Managing the display managers in the central module by
an option to select which display manager backend to use. adding an option to select which display manager backend
to use.
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
@ -138,43 +237,44 @@ options = {
Both approaches have problems. Both approaches have problems.
</para> </para>
<para> <para>
Making backends independent can quickly become hard to manage. For Making backends independent can quickly become hard to
display managers, there can be only one enabled at a time, but the manage. For display managers, there can be only one enabled
type system can not enforce this restriction as there is no at a time, but the type system can not enforce this
relation between each backend <literal>enable</literal> option. As restriction as there is no relation between each backend
a result, this restriction has to be done explicitely by adding <literal>enable</literal> option. As a result, this
assertions in each display manager backend module. restriction has to be done explicitely by adding assertions
in each display manager backend module.
</para> </para>
<para> <para>
On the other hand, managing the display managers backends in the On the other hand, managing the display managers backends in
central module will require to change the central module option the central module will require to change the central module
every time a new backend is added or removed. option every time a new backend is added or removed.
</para> </para>
<para> <para>
By using extensible option types, it is possible to create a By using extensible option types, it is possible to create a
placeholder option in the central module placeholder option in the central module
(<link linkend="ex-option-declaration-eot-service">Example: (<link linkend="ex-option-declaration-eot-service">Example:
Extensible type placeholder in the service module</link>), and to Extensible type placeholder in the service module</link>),
extend it in each backend module and to extend it in each backend module
(<link linkend="ex-option-declaration-eot-backend-gdm">Example: (<link linkend="ex-option-declaration-eot-backend-gdm">Example:
Extending Extending
<literal>services.xserver.displayManager.enable</literal> in the <literal>services.xserver.displayManager.enable</literal> in
<literal>gdm</literal> module</link>, the <literal>gdm</literal> module</link>,
<link linkend="ex-option-declaration-eot-backend-sddm">Example: <link linkend="ex-option-declaration-eot-backend-sddm">Example:
Extending Extending
<literal>services.xserver.displayManager.enable</literal> in the <literal>services.xserver.displayManager.enable</literal> in
<literal>sddm</literal> module</link>). the <literal>sddm</literal> module</link>).
</para> </para>
<para> <para>
As a result, <literal>displayManager.enable</literal> option As a result, <literal>displayManager.enable</literal> option
values can be added without changing the main service module file values can be added without changing the main service module
and the type system automatically enforce that there can only be a file and the type system automatically enforce that there
single display manager enabled. can only be a single display manager enabled.
</para> </para>
<anchor xml:id="ex-option-declaration-eot-service" /> <anchor xml:id="ex-option-declaration-eot-service" />
<para> <para>
<emphasis role="strong">Example: Extensible type placeholder in <emphasis role="strong">Example: Extensible type placeholder
the service module</emphasis> in the service module</emphasis>
</para> </para>
<programlisting language="bash"> <programlisting language="bash">
services.xserver.displayManager.enable = mkOption { services.xserver.displayManager.enable = mkOption {
@ -185,8 +285,8 @@ services.xserver.displayManager.enable = mkOption {
<anchor xml:id="ex-option-declaration-eot-backend-gdm" /> <anchor xml:id="ex-option-declaration-eot-backend-gdm" />
<para> <para>
<emphasis role="strong">Example: Extending <emphasis role="strong">Example: Extending
<literal>services.xserver.displayManager.enable</literal> in the <literal>services.xserver.displayManager.enable</literal> in
<literal>gdm</literal> module</emphasis> the <literal>gdm</literal> module</emphasis>
</para> </para>
<programlisting language="bash"> <programlisting language="bash">
services.xserver.displayManager.enable = mkOption { services.xserver.displayManager.enable = mkOption {
@ -196,8 +296,8 @@ services.xserver.displayManager.enable = mkOption {
<anchor xml:id="ex-option-declaration-eot-backend-sddm" /> <anchor xml:id="ex-option-declaration-eot-backend-sddm" />
<para> <para>
<emphasis role="strong">Example: Extending <emphasis role="strong">Example: Extending
<literal>services.xserver.displayManager.enable</literal> in the <literal>services.xserver.displayManager.enable</literal> in
<literal>sddm</literal> module</emphasis> the <literal>sddm</literal> module</emphasis>
</para> </para>
<programlisting language="bash"> <programlisting language="bash">
services.xserver.displayManager.enable = mkOption { services.xserver.displayManager.enable = mkOption {
@ -206,16 +306,19 @@ services.xserver.displayManager.enable = mkOption {
</programlisting> </programlisting>
<para> <para>
The placeholder declaration is a standard The placeholder declaration is a standard
<literal>mkOption</literal> declaration, but it is important that <literal>mkOption</literal> declaration, but it is important
extensible option declarations only use the that extensible option declarations only use the
<literal>type</literal> argument. <literal>type</literal> argument.
</para> </para>
<para> <para>
Extensible option types work with any of the composed variants of Extensible option types work with any of the composed
<literal>enum</literal> such as variants of <literal>enum</literal> such as
<literal>with types; nullOr (enum [ &quot;foo&quot; &quot;bar&quot; ])</literal> <literal>with types; nullOr (enum [ &quot;foo&quot; &quot;bar&quot; ])</literal>
or or
<literal>with types; listOf (enum [ &quot;foo&quot; &quot;bar&quot; ])</literal>. <literal>with types; listOf (enum [ &quot;foo&quot; &quot;bar&quot; ])</literal>.
</para> </para>
</section> </section>
</section> </section>
</section>
</section>
</section>