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:
parent
fdf7ede344
commit
c008b3d100
lib
nixos/doc/manual
@ -100,23 +100,48 @@ 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 =
|
||||||
{ default ? [ name ], example ? null }:
|
# Package set (a specific version of nixpkgs)
|
||||||
let default' = if !isList default then [ default ] else default;
|
pkgs:
|
||||||
in mkOption {
|
# Name for the package, shown in option description
|
||||||
type = lib.types.package;
|
name:
|
||||||
description = "The ${name} package to use.";
|
{ default ? [ name ], example ? null }:
|
||||||
default = attrByPath default'
|
let default' = if !isList default then [ default ] else default;
|
||||||
(throw "${concatStringsSep "." default'} cannot be found in pkgs") pkgs;
|
in mkOption {
|
||||||
defaultText = literalExpression ("pkgs." + concatStringsSep "." default');
|
type = lib.types.package;
|
||||||
${if example != null then "example" else null} = literalExpression
|
description = "The ${name} package to use.";
|
||||||
(if isList example then "pkgs." + concatStringsSep "." example else example);
|
default = attrByPath default'
|
||||||
};
|
(throw "${concatStringsSep "." default'} cannot be found in pkgs") pkgs;
|
||||||
|
defaultText = literalExpression ("pkgs." + concatStringsSep "." default');
|
||||||
|
${if example != null then "example" else null} = literalExpression
|
||||||
|
(if isList example then "pkgs." + concatStringsSep "." example else example);
|
||||||
|
};
|
||||||
|
|
||||||
/* This option accepts anything, but it does not produce any result.
|
/* This option accepts anything, but it does not produce any result.
|
||||||
|
|
||||||
|
@ -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 shouldn’t 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
|
||||||
|
@ -97,125 +97,228 @@ options = {
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
<section xml:id="sec-option-declarations-eot">
|
<section xml:id="sec-option-declarations-util">
|
||||||
<title>Extensible Option Types</title>
|
<title>Utility functions for common option patterns</title>
|
||||||
<para>
|
<section xml:id="sec-option-declarations-util-mkEnableOption">
|
||||||
Extensible option types is a feature that allow to extend certain
|
<title><literal>mkEnableOption</literal></title>
|
||||||
types declaration through multiple module files. This feature only
|
<para>
|
||||||
work with a restricted set of types, namely
|
Creates an Option attribute set for a boolean value option i.e
|
||||||
<literal>enum</literal> and <literal>submodules</literal> and any
|
an option to be toggled on or off.
|
||||||
composed forms of them.
|
</para>
|
||||||
</para>
|
<para>
|
||||||
<para>
|
This function takes a single string argument, the name of the
|
||||||
Extensible option types can be used for <literal>enum</literal>
|
thing to be toggled.
|
||||||
options that affects multiple modules, or as an alternative to
|
</para>
|
||||||
related <literal>enable</literal> options.
|
<para>
|
||||||
</para>
|
The option’s description is <quote>Whether to enable
|
||||||
<para>
|
<name>.</quote>.
|
||||||
As an example, we will take the case of display managers. There is
|
</para>
|
||||||
a central display manager module for generic display manager
|
<para>
|
||||||
options and a module file per display manager backend (sddm, gdm
|
For example:
|
||||||
...).
|
</para>
|
||||||
</para>
|
<anchor xml:id="ex-options-declarations-util-mkEnableOption-magic" />
|
||||||
<para>
|
<programlisting language="bash">
|
||||||
There are two approach to this module structure:
|
lib.mkEnableOption "magic"
|
||||||
</para>
|
# is like
|
||||||
<itemizedlist>
|
lib.mkOption {
|
||||||
<listitem>
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
example = true;
|
||||||
|
description = "Whether to enable magic.";
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<section xml:id="sec-option-declarations-util-mkPackageOption">
|
||||||
|
<title><literal>mkPackageOption</literal></title>
|
||||||
<para>
|
<para>
|
||||||
Managing the display managers independently by adding an
|
Usage:
|
||||||
enable option to every display manager module backend. (NixOS)
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
<programlisting language="bash">
|
||||||
<listitem>
|
mkPackageOption pkgs "name" { default = [ "path" "in" "pkgs" ]; example = "literal example"; }
|
||||||
|
</programlisting>
|
||||||
<para>
|
<para>
|
||||||
Managing the display managers in the central module by adding
|
Creates an Option attribute set for an option that specifies
|
||||||
an option to select which display manager backend to use.
|
the package a module should use for some purpose.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
<para>
|
||||||
</itemizedlist>
|
<emphasis role="strong">Note</emphasis>: You shouldn’t
|
||||||
<para>
|
necessarily make package options for all of your modules. You
|
||||||
Both approaches have problems.
|
can always overwrite a specific package throughout nixpkgs by
|
||||||
</para>
|
using
|
||||||
<para>
|
<link xlink:href="https://nixos.org/manual/nixpkgs/stable/#chap-overlays">nixpkgs
|
||||||
Making backends independent can quickly become hard to manage. For
|
overlays</link>.
|
||||||
display managers, there can be only one enabled at a time, but the
|
</para>
|
||||||
type system can not enforce this restriction as there is no
|
<para>
|
||||||
relation between each backend <literal>enable</literal> option. As
|
The default package is specified as a list of strings
|
||||||
a result, this restriction has to be done explicitely by adding
|
representing its attribute path in nixpkgs. Because of this,
|
||||||
assertions in each display manager backend module.
|
you need to pass nixpkgs itself as the first argument.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
On the other hand, managing the display managers backends in the
|
The second argument is the name of the option, used in the
|
||||||
central module will require to change the central module option
|
description <quote>The <name> package to use.</quote>.
|
||||||
every time a new backend is added or removed.
|
You can also pass an example value, either a literal string or
|
||||||
</para>
|
a package’s attribute path.
|
||||||
<para>
|
</para>
|
||||||
By using extensible option types, it is possible to create a
|
<para>
|
||||||
placeholder option in the central module
|
You can omit the default path if the name of the option is
|
||||||
(<link linkend="ex-option-declaration-eot-service">Example:
|
also attribute path in nixpkgs.
|
||||||
Extensible type placeholder in the service module</link>), and to
|
</para>
|
||||||
extend it in each backend module
|
<anchor xml:id="ex-options-declarations-util-mkPackageOption" />
|
||||||
(<link linkend="ex-option-declaration-eot-backend-gdm">Example:
|
<para>
|
||||||
Extending
|
Examples:
|
||||||
<literal>services.xserver.displayManager.enable</literal> in the
|
</para>
|
||||||
<literal>gdm</literal> module</link>,
|
<anchor xml:id="ex-options-declarations-util-mkPackageOption-hello" />
|
||||||
<link linkend="ex-option-declaration-eot-backend-sddm">Example:
|
<programlisting language="bash">
|
||||||
Extending
|
lib.mkPackageOption pkgs "hello" { }
|
||||||
<literal>services.xserver.displayManager.enable</literal> in the
|
# is like
|
||||||
<literal>sddm</literal> module</link>).
|
lib.mkOption {
|
||||||
</para>
|
type = lib.types.package;
|
||||||
<para>
|
default = pkgs.hello;
|
||||||
As a result, <literal>displayManager.enable</literal> option
|
defaultText = lib.literalExpression "pkgs.hello";
|
||||||
values can be added without changing the main service module file
|
description = "The hello package to use.";
|
||||||
and the type system automatically enforce that there can only be a
|
}
|
||||||
single display manager enabled.
|
</programlisting>
|
||||||
</para>
|
<anchor xml:id="ex-options-declarations-util-mkPackageOption-ghc" />
|
||||||
<anchor xml:id="ex-option-declaration-eot-service" />
|
<programlisting language="bash">
|
||||||
<para>
|
lib.mkPackageOption pkgs "GHC" {
|
||||||
<emphasis role="strong">Example: Extensible type placeholder in
|
default = [ "ghc" ];
|
||||||
the service module</emphasis>
|
example = "pkgs.haskell.package.ghc921.ghc.withPackages (hkgs: [ hkgs.primes ])";
|
||||||
</para>
|
}
|
||||||
<programlisting language="bash">
|
# 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.";
|
||||||
|
}
|
||||||
|
</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 approach to this module structure:
|
||||||
|
</para>
|
||||||
|
<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>
|
||||||
|
Both approaches 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
|
||||||
|
(<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 enforce 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 {
|
services.xserver.displayManager.enable = mkOption {
|
||||||
description = "Display manager to use";
|
description = "Display manager to use";
|
||||||
type = with types; nullOr (enum [ ]);
|
type = with types; nullOr (enum [ ]);
|
||||||
};
|
};
|
||||||
</programlisting>
|
</programlisting>
|
||||||
<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 {
|
||||||
type = with types; nullOr (enum [ "gdm" ]);
|
type = with types; nullOr (enum [ "gdm" ]);
|
||||||
};
|
};
|
||||||
</programlisting>
|
</programlisting>
|
||||||
<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 {
|
||||||
type = with types; nullOr (enum [ "sddm" ]);
|
type = with types; nullOr (enum [ "sddm" ]);
|
||||||
};
|
};
|
||||||
</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 [ "foo" "bar" ])</literal>
|
<literal>with types; nullOr (enum [ "foo" "bar" ])</literal>
|
||||||
or
|
or
|
||||||
<literal>with types; listOf (enum [ "foo" "bar" ])</literal>.
|
<literal>with types; listOf (enum [ "foo" "bar" ])</literal>.
|
||||||
</para>
|
</para>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
Loading…
Reference in New Issue
Block a user