mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-12-04 21:03:15 +00:00
07cb3bf3cc
Update the pinned channel in `md-to-db`, which bumps the Pandoc version, which fixes https://github.com/NixOS/nixpkgs/issues/125511 maybe.
421 lines
14 KiB
XML
421 lines
14 KiB
XML
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-settings-options">
|
||
<title>Options for Program Settings</title>
|
||
<para>
|
||
Many programs have configuration files where program-specific
|
||
settings can be declared. File formats can be separated into two
|
||
categories:
|
||
</para>
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>
|
||
Nix-representable ones: These can trivially be mapped to a
|
||
subset of Nix syntax. E.g. JSON is an example, since its values
|
||
like <literal>{"foo":{"bar":10}}</literal>
|
||
can be mapped directly to Nix:
|
||
<literal>{ foo = { bar = 10; }; }</literal>. Other examples are
|
||
INI, YAML and TOML. The following section explains the
|
||
convention for these settings.
|
||
</para>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
Non-nix-representable ones: These can’t be trivially mapped to a
|
||
subset of Nix syntax. Most generic programming languages are in
|
||
this group, e.g. bash, since the statement
|
||
<literal>if true; then echo hi; fi</literal> doesn’t have a
|
||
trivial representation in Nix.
|
||
</para>
|
||
<para>
|
||
Currently there are no fixed conventions for these, but it is
|
||
common to have a <literal>configFile</literal> option for
|
||
setting the configuration file path directly. The default value
|
||
of <literal>configFile</literal> can be an auto-generated file,
|
||
with convenient options for controlling the contents. For
|
||
example an option of type <literal>attrsOf str</literal> can be
|
||
used for representing environment variables which generates a
|
||
section like <literal>export FOO="foo"</literal>.
|
||
Often it can also be useful to also include an
|
||
<literal>extraConfig</literal> option of type
|
||
<literal>lines</literal> to allow arbitrary text after the
|
||
autogenerated part of the file.
|
||
</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
<section xml:id="sec-settings-nix-representable">
|
||
<title>Nix-representable Formats (JSON, YAML, TOML, INI, …)</title>
|
||
<para>
|
||
By convention, formats like this are handled with a generic
|
||
<literal>settings</literal> option, representing the full program
|
||
configuration as a Nix value. The type of this option should
|
||
represent the format. The most common formats have a predefined
|
||
type and string generator already declared under
|
||
<literal>pkgs.formats</literal>:
|
||
</para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>pkgs.formats.javaProperties</literal> {
|
||
<emphasis><literal>comment</literal></emphasis> ?
|
||
<literal>"Generated with Nix"</literal> }
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
A function taking an attribute set with values
|
||
</para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>comment</literal>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
A string to put at the start of the file in a comment.
|
||
It can have multiple lines.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
<para>
|
||
It returns the <literal>type</literal>:
|
||
<literal>attrsOf str</literal> and a function
|
||
<literal>generate</literal> to build a Java
|
||
<literal>.properties</literal> file, taking care of the
|
||
correct escaping, etc.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>pkgs.formats.json</literal> { }
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
A function taking an empty attribute set (for future
|
||
extensibility) and returning a set with JSON-specific
|
||
attributes <literal>type</literal> and
|
||
<literal>generate</literal> as specified
|
||
<link linkend="pkgs-formats-result">below</link>.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>pkgs.formats.yaml</literal> { }
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
A function taking an empty attribute set (for future
|
||
extensibility) and returning a set with YAML-specific
|
||
attributes <literal>type</literal> and
|
||
<literal>generate</literal> as specified
|
||
<link linkend="pkgs-formats-result">below</link>.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>pkgs.formats.ini</literal> {
|
||
<emphasis><literal>listsAsDuplicateKeys</literal></emphasis> ?
|
||
false, <emphasis><literal>listToValue</literal></emphasis> ?
|
||
null, ... }
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
A function taking an attribute set with values
|
||
</para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>listsAsDuplicateKeys</literal>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
A boolean for controlling whether list values can be
|
||
used to represent duplicate INI keys
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>listToValue</literal>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
A function for turning a list of values into a single
|
||
value.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
<para>
|
||
It returns a set with INI-specific attributes
|
||
<literal>type</literal> and <literal>generate</literal> as
|
||
specified <link linkend="pkgs-formats-result">below</link>.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>pkgs.formats.toml</literal> { }
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
A function taking an empty attribute set (for future
|
||
extensibility) and returning a set with TOML-specific
|
||
attributes <literal>type</literal> and
|
||
<literal>generate</literal> as specified
|
||
<link linkend="pkgs-formats-result">below</link>.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>pkgs.formats.elixirConf { elixir ? pkgs.elixir }</literal>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
A function taking an attribute set with values
|
||
</para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>elixir</literal>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
The Elixir package which will be used to format the
|
||
generated output
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
<para>
|
||
It returns a set with Elixir-Config-specific attributes
|
||
<literal>type</literal>, <literal>lib</literal>, and
|
||
<literal>generate</literal> as specified
|
||
<link linkend="pkgs-formats-result">below</link>.
|
||
</para>
|
||
<para>
|
||
The <literal>lib</literal> attribute contains functions to
|
||
be used in settings, for generating special Elixir values:
|
||
</para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>mkRaw elixirCode</literal>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
Outputs the given string as raw Elixir code
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>mkGetEnv { envVariable, fallback ? null }</literal>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
Makes the configuration fetch an environment variable
|
||
at runtime
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>mkAtom atom</literal>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
Outputs the given string as an Elixir atom, instead of
|
||
the default Elixir binary string. Note: lowercase
|
||
atoms still needs to be prefixed with
|
||
<literal>:</literal>
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>mkTuple array</literal>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
Outputs the given array as an Elixir tuple, instead of
|
||
the default Elixir list
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>mkMap attrset</literal>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
Outputs the given attribute set as an Elixir map,
|
||
instead of the default Elixir keyword list
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
<para xml:id="pkgs-formats-result">
|
||
These functions all return an attribute set with these values:
|
||
</para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>type</literal>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
A module system type representing a value of the format
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>lib</literal>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
Utility functions for convenience, or special interactions
|
||
with the format. This attribute is optional. It may contain
|
||
inside a <literal>types</literal> attribute containing types
|
||
specific to this format.
|
||
</para>
|
||
</listitem>
|
||
</varlistentry>
|
||
<varlistentry>
|
||
<term>
|
||
<literal>generate</literal>
|
||
<emphasis><literal>filename jsonValue</literal></emphasis>
|
||
</term>
|
||
<listitem>
|
||
<para>
|
||
A function that can render a value of the format to a file.
|
||
Returns a file path.
|
||
</para>
|
||
<note>
|
||
<para>
|
||
This function puts the value contents in the Nix store. So
|
||
this should be avoided for secrets.
|
||
</para>
|
||
</note>
|
||
</listitem>
|
||
</varlistentry>
|
||
</variablelist>
|
||
<anchor xml:id="ex-settings-nix-representable" />
|
||
<para>
|
||
<emphasis role="strong">Example: Module with conventional
|
||
<literal>settings</literal> option</emphasis>
|
||
</para>
|
||
<para>
|
||
The following shows a module for an example program that uses a
|
||
JSON configuration file. It demonstrates how above values can be
|
||
used, along with some other related best practices. See the
|
||
comments for explanations.
|
||
</para>
|
||
<programlisting language="nix">
|
||
{ options, config, lib, pkgs, ... }:
|
||
let
|
||
cfg = config.services.foo;
|
||
# Define the settings format used for this program
|
||
settingsFormat = pkgs.formats.json {};
|
||
in {
|
||
|
||
options.services.foo = {
|
||
enable = lib.mkEnableOption "foo service";
|
||
|
||
settings = lib.mkOption {
|
||
# Setting this type allows for correct merging behavior
|
||
type = settingsFormat.type;
|
||
default = {};
|
||
description = ''
|
||
Configuration for foo, see
|
||
<link xlink:href="https://example.com/docs/foo"/>
|
||
for supported settings.
|
||
'';
|
||
};
|
||
};
|
||
|
||
config = lib.mkIf cfg.enable {
|
||
# We can assign some default settings here to make the service work by just
|
||
# enabling it. We use `mkDefault` for values that can be changed without
|
||
# problems
|
||
services.foo.settings = {
|
||
# Fails at runtime without any value set
|
||
log_level = lib.mkDefault "WARN";
|
||
|
||
# We assume systemd's `StateDirectory` is used, so we require this value,
|
||
# therefore no mkDefault
|
||
data_path = "/var/lib/foo";
|
||
|
||
# Since we use this to create a user we need to know the default value at
|
||
# eval time
|
||
user = lib.mkDefault "foo";
|
||
};
|
||
|
||
environment.etc."foo.json".source =
|
||
# The formats generator function takes a filename and the Nix value
|
||
# representing the format value and produces a filepath with that value
|
||
# rendered in the format
|
||
settingsFormat.generate "foo-config.json" cfg.settings;
|
||
|
||
# We know that the `user` attribute exists because we set a default value
|
||
# for it above, allowing us to use it without worries here
|
||
users.users.${cfg.settings.user} = { isSystemUser = true; };
|
||
|
||
# ...
|
||
};
|
||
}
|
||
</programlisting>
|
||
<section xml:id="sec-settings-attrs-options">
|
||
<title>Option declarations for attributes</title>
|
||
<para>
|
||
Some <literal>settings</literal> attributes may deserve some
|
||
extra care. They may need a different type, default or merging
|
||
behavior, or they are essential options that should show their
|
||
documentation in the manual. This can be done using
|
||
<xref linkend="sec-freeform-modules" />.
|
||
</para>
|
||
<para>
|
||
We extend above example using freeform modules to declare an
|
||
option for the port, which will enforce it to be a valid integer
|
||
and make it show up in the manual.
|
||
</para>
|
||
<anchor xml:id="ex-settings-typed-attrs" />
|
||
<para>
|
||
<emphasis role="strong">Example: Declaring a type-checked
|
||
<literal>settings</literal> attribute</emphasis>
|
||
</para>
|
||
<programlisting language="nix">
|
||
settings = lib.mkOption {
|
||
type = lib.types.submodule {
|
||
|
||
freeformType = settingsFormat.type;
|
||
|
||
# Declare an option for the port such that the type is checked and this option
|
||
# is shown in the manual.
|
||
options.port = lib.mkOption {
|
||
type = lib.types.port;
|
||
default = 8080;
|
||
description = ''
|
||
Which port this service should listen on.
|
||
'';
|
||
};
|
||
|
||
};
|
||
default = {};
|
||
description = ''
|
||
Configuration for Foo, see
|
||
<link xlink:href="https://example.com/docs/foo"/>
|
||
for supported values.
|
||
'';
|
||
};
|
||
</programlisting>
|
||
</section>
|
||
</section>
|
||
</section>
|