 b8336c2b8a
			
		
	
	
		b8336c2b8a
		
			
		
	
	
	
	
		
			
			Allows coercing lists to values. E.g.
  formats.ini { listToValue = lib.concatMapStringsSep ", " (lib.generators.mkValueStringDefault {}); }
		
	
			
		
			
				
	
	
		
			227 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
		
			9.4 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-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:
 | |
|    <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>
 | |
|  </para>
 | |
|  <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>:
 | |
|      <variablelist>
 | |
|        <varlistentry>
 | |
|          <term>
 | |
|            <varname>pkgs.formats.json</varname> { }
 | |
|          </term>
 | |
|          <listitem>
 | |
|            <para>
 | |
|              A function taking an empty attribute set (for future extensibility) and returning a set with JSON-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
 | |
|            </para>
 | |
|          </listitem>
 | |
|        </varlistentry>
 | |
|        <varlistentry>
 | |
|          <term>
 | |
|            <varname>pkgs.formats.yaml</varname> { }
 | |
|          </term>
 | |
|          <listitem>
 | |
|            <para>
 | |
|              A function taking an empty attribute set (for future extensibility) and returning a set with YAML-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
 | |
|            </para>
 | |
|          </listitem>
 | |
|        </varlistentry>
 | |
|        <varlistentry>
 | |
|          <term>
 | |
|            <varname>pkgs.formats.ini</varname> { <replaceable>listsAsDuplicateKeys</replaceable> ? false, <replaceable>listToValue</replaceable> ? null, ... }
 | |
|          </term>
 | |
|          <listitem>
 | |
|            <para>
 | |
|              A function taking an attribute set with values
 | |
|              <variablelist>
 | |
|                <varlistentry>
 | |
|                  <term>
 | |
|                    <varname>listsAsDuplicateKeys</varname>
 | |
|                  </term>
 | |
|                  <listitem>
 | |
|                    <para>
 | |
|                      A boolean for controlling whether list values can be used to represent duplicate INI keys
 | |
|                    </para>
 | |
|                  </listitem>
 | |
|                </varlistentry>
 | |
|                <varlistentry>
 | |
|                  <term>
 | |
|                    <varname>listToValue</varname>
 | |
|                  </term>
 | |
|                  <listitem>
 | |
|                    <para>
 | |
|                      A function for turning a list of values into a single value.
 | |
|                    </para>
 | |
|                  </listitem>
 | |
|                </varlistentry>
 | |
|              </variablelist>
 | |
|             It returns a set with INI-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
 | |
|            </para>
 | |
|          </listitem>
 | |
|        </varlistentry>
 | |
|        <varlistentry>
 | |
|          <term>
 | |
|            <varname>pkgs.formats.toml</varname> { }
 | |
|          </term>
 | |
|          <listitem>
 | |
|            <para>
 | |
|              A function taking an empty attribute set (for future extensibility) and returning a set with TOML-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
 | |
|            </para>
 | |
|          </listitem>
 | |
|        </varlistentry>
 | |
|      </variablelist>
 | |
| 
 | |
|    </para>
 | |
|    <para xml:id="pkgs-formats-result">
 | |
|      These functions all return an attribute set with these values:
 | |
|     <variablelist>
 | |
|       <varlistentry>
 | |
|         <term>
 | |
|           <varname>type</varname>
 | |
|         </term>
 | |
|         <listitem>
 | |
|           <para>
 | |
|             A module system type representing a value of the format
 | |
|           </para>
 | |
|         </listitem>
 | |
|       </varlistentry>
 | |
|       <varlistentry>
 | |
|         <term>
 | |
|           <varname>generate</varname> <replaceable>filename</replaceable> <replaceable>jsonValue</replaceable>
 | |
|         </term>
 | |
|         <listitem>
 | |
|           <para>
 | |
|            A function that can render a value of the format to a file. Returns a file path.
 | |
|            <note>
 | |
|             <para>
 | |
|              This function puts the value contents in the Nix store. So this should be avoided for secrets.
 | |
|             </para>
 | |
|            </note>
 | |
|           </para>
 | |
|         </listitem>
 | |
|       </varlistentry>
 | |
|     </variablelist>
 | |
|    </para>
 | |
|    <example xml:id="ex-settings-nix-representable">
 | |
|      <title>Module with conventional <literal>settings</literal> option</title>
 | |
|      <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>
 | |
| { 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>
 | |
|    </example>
 | |
|    <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'/>.
 | |
|      <example xml:id="ex-settings-typed-attrs">
 | |
|       <title>Declaring a type-checked <literal>settings</literal> attribute</title>
 | |
|       <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>
 | |
| <programlisting>
 | |
| 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>
 | |
|      </example>
 | |
|     </para>
 | |
|    </section>
 | |
|  </section>
 | |
| 
 | |
| </section>
 |