From 25d75155f39d293d16ecd6aab70024a8740e0baa Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Tue, 4 Aug 2020 01:29:43 +0200 Subject: [PATCH] nixos/doc: Add freeform modules documentation Co-Authored-By: Robert Hensing --- .../manual/development/freeform-modules.xml | 68 +++++++++++++++++++ .../manual/development/settings-options.xml | 41 ++++++++++- .../manual/development/writing-modules.xml | 1 + 3 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 nixos/doc/manual/development/freeform-modules.xml 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 @@ +
+ Freeform modules + + 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 attrsOf options in order to accept all attribute names. + + + This feature can be enabled by using the attribute freeformType 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 config set. Since this feature nullifies name checking for entire option trees, it is only recommended for use in submodules. + + + Freeform submodule + + The following shows a submodule assigning a freeform type that allows arbitrary attributes with str values below settings, but also declares an option for the settings.port attribute to have it type-checked and assign a default value. See for a more complete example. + + +{ 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; + }; + + }; + }; +} + + + And the following shows what such a module then allows + + +{ + # 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"; +} + + + + + Freeform attributes cannot depend on other attributes of the same set without infinite recursion: + +{ + # This throws infinite recursion encountered + settings.logLevel = lib.mkIf (config.settings.port == 80) "debug"; +} + + To prevent this, declare options for all attributes that need to depend on others. For above example this means to declare logLevel to be an option. + + +
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 <link xlink:href="https://example.com/docs/foo"/> - 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} = {}; # ... }; } +
+ Option declarations for attributes + + Some settings 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 . + + Declaring a type-checked <literal>settings</literal> attribute + + 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. + + +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. + ''; +}; + + + +
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 { +