summary refs log tree commit diff
path: root/nixos/doc
diff options
context:
space:
mode:
authorRobert Hensing <roberth@users.noreply.github.com>2020-08-15 12:13:58 +0200
committerGitHub <noreply@github.com>2020-08-15 12:13:58 +0200
commit6d0a85fe528e020eb7d8eb78d33ee87055c01c74 (patch)
treecd0e99185243f514ba6a4004d8697e019681db55 /nixos/doc
parent375611df00b01c668fd82fc0632cd8aec826b5ec (diff)
parent25d75155f39d293d16ecd6aab70024a8740e0baa (diff)
downloadnixpkgs-6d0a85fe528e020eb7d8eb78d33ee87055c01c74.tar
nixpkgs-6d0a85fe528e020eb7d8eb78d33ee87055c01c74.tar.gz
nixpkgs-6d0a85fe528e020eb7d8eb78d33ee87055c01c74.tar.bz2
nixpkgs-6d0a85fe528e020eb7d8eb78d33ee87055c01c74.tar.lz
nixpkgs-6d0a85fe528e020eb7d8eb78d33ee87055c01c74.tar.xz
nixpkgs-6d0a85fe528e020eb7d8eb78d33ee87055c01c74.tar.zst
nixpkgs-6d0a85fe528e020eb7d8eb78d33ee87055c01c74.zip
Merge pull request #82743 from Infinisil/partially-typed-v2
Freeform modules
Diffstat (limited to 'nixos/doc')
-rw-r--r--nixos/doc/manual/development/freeform-modules.xml68
-rw-r--r--nixos/doc/manual/development/settings-options.xml41
-rw-r--r--nixos/doc/manual/development/writing-modules.xml1
3 files changed, 108 insertions, 2 deletions
diff --git a/nixos/doc/manual/development/freeform-modules.xml b/nixos/doc/manual/development/freeform-modules.xml
new file mode 100644
index 00000000000..257e6b11bf0
--- /dev/null
+++ b/nixos/doc/manual/development/freeform-modules.xml
@@ -0,0 +1,68 @@
+<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-freeform-modules">
+ <title>Freeform modules</title>
+ <para>
+  Freeform modules allow you to define values for option paths that have not been declared explicitly. This can be used to add attribute-specific types to what would otherwise have to be <literal>attrsOf</literal> options in order to accept all attribute names.
+ </para>
+ <para>
+  This feature can be enabled by using the attribute <literal>freeformType</literal> to define a freeform type. By doing this, all assignments without an associated option will be merged using the freeform type and combined into the resulting <literal>config</literal> set. Since this feature nullifies name checking for entire option trees, it is only recommended for use in submodules.
+ </para>
+ <example xml:id="ex-freeform-module">
+  <title>Freeform submodule</title>
+  <para>
+   The following shows a submodule assigning a freeform type that allows arbitrary attributes with <literal>str</literal> values below <literal>settings</literal>, but also declares an option for the <literal>settings.port</literal> attribute to have it type-checked and assign a default value. See <xref linkend="ex-settings-typed-attrs"/> for a more complete example.
+  </para>
+ <programlisting>
+{ lib, config, ... }: {
+
+  options.settings = lib.mkOption {
+    type = lib.types.submodule {
+
+      freeformType = with lib.types; attrsOf str;
+
+      # We want this attribute to be checked for the correct type
+      options.port = lib.mkOption {
+        type = lib.types.port;
+        # Declaring the option also allows defining a default value
+        default = 8080;
+      };
+
+    };
+  };
+}
+ </programlisting>
+ <para>
+  And the following shows what such a module then allows
+ </para>
+ <programlisting>
+{
+  # Not a declared option, but the freeform type allows this
+  settings.logLevel = "debug";
+
+  # Not allowed because the the freeform type only allows strings
+  # settings.enable = true;
+
+  # Allowed because there is a port option declared
+  settings.port = 80;
+
+  # Not allowed because the port option doesn't allow strings
+  # settings.port = "443";
+}
+ </programlisting>
+ </example>
+ <note>
+  <para>
+   Freeform attributes cannot depend on other attributes of the same set without infinite recursion:
+<programlisting>
+{
+  # This throws infinite recursion encountered
+  settings.logLevel = lib.mkIf (config.settings.port == 80) "debug";
+}
+</programlisting>
+   To prevent this, declare options for all attributes that need to depend on others. For above example this means to declare <literal>logLevel</literal> to be an option.
+  </para>
+ </note>
+</section>
diff --git a/nixos/doc/manual/development/settings-options.xml b/nixos/doc/manual/development/settings-options.xml
index 84895adb444..c99c3af92f8 100644
--- a/nixos/doc/manual/development/settings-options.xml
+++ b/nixos/doc/manual/development/settings-options.xml
@@ -137,7 +137,7 @@ in {
       description = ''
         Configuration for foo, see
         &lt;link xlink:href="https://example.com/docs/foo"/&gt;
-        for supported values.
+        for supported settings.
       '';
     };
   };
@@ -167,13 +167,50 @@ in {
 
     # 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} = {}
+    users.users.${cfg.settings.user} = {};
 
     # ...
   };
 }
 </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
+    &lt;link xlink:href="https://example.com/docs/foo"/&gt;
+    for supported values.
+  '';
+};
+</programlisting>
+     </example>
+    </para>
+   </section>
  </section>
 
 </section>
diff --git a/nixos/doc/manual/development/writing-modules.xml b/nixos/doc/manual/development/writing-modules.xml
index 602f134f9cb..d244356dbed 100644
--- a/nixos/doc/manual/development/writing-modules.xml
+++ b/nixos/doc/manual/development/writing-modules.xml
@@ -183,5 +183,6 @@ in {
  <xi:include href="meta-attributes.xml" />
  <xi:include href="importing-modules.xml" />
  <xi:include href="replace-modules.xml" />
+ <xi:include href="freeform-modules.xml" />
  <xi:include href="settings-options.xml" />
 </chapter>