From 165d6bd20c478c8c4f201c26eaa4c62e3c1b87ce Mon Sep 17 00:00:00 2001 From: Bobby Rong Date: Sat, 3 Jul 2021 22:20:26 +0800 Subject: [PATCH] nixos: nixos/doc/manual/development/settings-options.xml to CommonMark --- .../development/settings-options.section.md | 192 ++++++++++++ .../manual/development/settings-options.xml | 226 -------------- .../manual/development/writing-modules.xml | 4 +- .../development/settings-options.section.xml | 285 ++++++++++++++++++ 4 files changed, 479 insertions(+), 228 deletions(-) create mode 100644 nixos/doc/manual/development/settings-options.section.md delete mode 100644 nixos/doc/manual/development/settings-options.xml create mode 100644 nixos/doc/manual/from_md/development/settings-options.section.xml diff --git a/nixos/doc/manual/development/settings-options.section.md b/nixos/doc/manual/development/settings-options.section.md new file mode 100644 index 000000000000..58a3d8448af5 --- /dev/null +++ b/nixos/doc/manual/development/settings-options.section.md @@ -0,0 +1,192 @@ +# Options for Program Settings {#sec-settings-options} + +Many programs have configuration files where program-specific settings +can be declared. File formats can be separated into two categories: + +- Nix-representable ones: These can trivially be mapped to a subset of + Nix syntax. E.g. JSON is an example, since its values like + `{"foo":{"bar":10}}` can be mapped directly to Nix: + `{ foo = { bar = 10; }; }`. Other examples are INI, YAML and TOML. + The following section explains the convention for these settings. + +- 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 `if true; then echo hi; fi` + doesn\'t have a trivial representation in Nix. + + Currently there are no fixed conventions for these, but it is common + to have a `configFile` option for setting the configuration file + path directly. The default value of `configFile` can be an + auto-generated file, with convenient options for controlling the + contents. For example an option of type `attrsOf str` can be used + for representing environment variables which generates a section + like `export FOO="foo"`. Often it can also be useful to also include + an `extraConfig` option of type `lines` to allow arbitrary text + after the autogenerated part of the file. + +## Nix-representable Formats (JSON, YAML, TOML, INI, \...) {#sec-settings-nix-representable} + +By convention, formats like this are handled with a generic `settings` +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 +`pkgs.formats`: + +`pkgs.formats.json` { } + +: A function taking an empty attribute set (for future extensibility) + and returning a set with JSON-specific attributes `type` and + `generate` as specified [below](#pkgs-formats-result). + +`pkgs.formats.yaml` { } + +: A function taking an empty attribute set (for future extensibility) + and returning a set with YAML-specific attributes `type` and + `generate` as specified [below](#pkgs-formats-result). + +`pkgs.formats.ini` { *`listsAsDuplicateKeys`* ? false, *`listToValue`* ? null, \... } + +: A function taking an attribute set with values + + `listsAsDuplicateKeys` + + : A boolean for controlling whether list values can be used to + represent duplicate INI keys + + `listToValue` + + : A function for turning a list of values into a single value. + + It returns a set with INI-specific attributes `type` and `generate` + as specified [below](#pkgs-formats-result). + +`pkgs.formats.toml` { } + +: A function taking an empty attribute set (for future extensibility) + and returning a set with TOML-specific attributes `type` and + `generate` as specified [below](#pkgs-formats-result). + +::: {#pkgs-formats-result} +These functions all return an attribute set with these values: +::: + +`type` + +: A module system type representing a value of the format + +`generate` *`filename jsonValue`* + +: A function that can render a value of the format to a file. Returns + a file path. + + ::: {.note} + This function puts the value contents in the Nix store. So this + should be avoided for secrets. + ::: + +::: {#ex-settings-nix-representable .example} +::: {.title} +**Example: Module with conventional `settings` option** +::: +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. + +```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 + + 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; }; + + # ... + }; +} +``` +::: + +### Option declarations for attributes {#sec-settings-attrs-options} + +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 [](#sec-freeform-modules). + +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. + +::: {#ex-settings-typed-attrs .example} +::: {.title} +**Example: Declaring a type-checked `settings` attribute** +::: +```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 + + for supported values. + ''; +}; +``` +::: diff --git a/nixos/doc/manual/development/settings-options.xml b/nixos/doc/manual/development/settings-options.xml deleted file mode 100644 index 7292cac62b70..000000000000 --- a/nixos/doc/manual/development/settings-options.xml +++ /dev/null @@ -1,226 +0,0 @@ -
- Options for Program Settings - - - Many programs have configuration files where program-specific settings can be declared. File formats can be separated into two categories: - - - - Nix-representable ones: These can trivially be mapped to a subset of Nix syntax. E.g. JSON is an example, since its values like {"foo":{"bar":10}} can be mapped directly to Nix: { foo = { bar = 10; }; }. Other examples are INI, YAML and TOML. The following section explains the convention for these settings. - - - - - 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 if true; then echo hi; fi doesn't have a trivial representation in Nix. - - - Currently there are no fixed conventions for these, but it is common to have a configFile option for setting the configuration file path directly. The default value of configFile can be an auto-generated file, with convenient options for controlling the contents. For example an option of type attrsOf str can be used for representing environment variables which generates a section like export FOO="foo". Often it can also be useful to also include an extraConfig option of type lines to allow arbitrary text after the autogenerated part of the file. - - - - -
- Nix-representable Formats (JSON, YAML, TOML, INI, ...) - - By convention, formats like this are handled with a generic settings 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 pkgs.formats: - - - - pkgs.formats.json { } - - - - A function taking an empty attribute set (for future extensibility) and returning a set with JSON-specific attributes type and generate as specified below. - - - - - - pkgs.formats.yaml { } - - - - A function taking an empty attribute set (for future extensibility) and returning a set with YAML-specific attributes type and generate as specified below. - - - - - - pkgs.formats.ini { listsAsDuplicateKeys ? false, listToValue ? null, ... } - - - - A function taking an attribute set with values - - - - listsAsDuplicateKeys - - - - A boolean for controlling whether list values can be used to represent duplicate INI keys - - - - - - listToValue - - - - A function for turning a list of values into a single value. - - - - - It returns a set with INI-specific attributes type and generate as specified below. - - - - - - pkgs.formats.toml { } - - - - A function taking an empty attribute set (for future extensibility) and returning a set with TOML-specific attributes type and generate as specified below. - - - - - - - - These functions all return an attribute set with these values: - - - - type - - - - A module system type representing a value of the format - - - - - - generate filename jsonValue - - - - A function that can render a value of the format to a file. Returns a file path. - - - This function puts the value contents in the Nix store. So this should be avoided for secrets. - - - - - - - - - Module with conventional <literal>settings</literal> option - - 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. - - -{ 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; }; - - # ... - }; -} - - -
- 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 7cf7c9b62994..167976247091 100644 --- a/nixos/doc/manual/development/writing-modules.xml +++ b/nixos/doc/manual/development/writing-modules.xml @@ -186,6 +186,6 @@ in { - - + + diff --git a/nixos/doc/manual/from_md/development/settings-options.section.xml b/nixos/doc/manual/from_md/development/settings-options.section.xml new file mode 100644 index 000000000000..c9430b77579c --- /dev/null +++ b/nixos/doc/manual/from_md/development/settings-options.section.xml @@ -0,0 +1,285 @@ +
+ Options for Program Settings + + Many programs have configuration files where program-specific + settings can be declared. File formats can be separated into two + categories: + + + + + Nix-representable ones: These can trivially be mapped to a + subset of Nix syntax. E.g. JSON is an example, since its values + like {"foo":{"bar":10}} + can be mapped directly to Nix: + { foo = { bar = 10; }; }. Other examples are + INI, YAML and TOML. The following section explains the + convention for these settings. + + + + + 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 + if true; then echo hi; fi doesn't have a + trivial representation in Nix. + + + Currently there are no fixed conventions for these, but it is + common to have a configFile option for + setting the configuration file path directly. The default value + of configFile can be an auto-generated file, + with convenient options for controlling the contents. For + example an option of type attrsOf str can be + used for representing environment variables which generates a + section like export FOO="foo". + Often it can also be useful to also include an + extraConfig option of type + lines to allow arbitrary text after the + autogenerated part of the file. + + + +
+ Nix-representable Formats (JSON, YAML, TOML, INI, + ...) + + By convention, formats like this are handled with a generic + settings 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 + pkgs.formats: + + + + + pkgs.formats.json { } + + + + A function taking an empty attribute set (for future + extensibility) and returning a set with JSON-specific + attributes type and + generate as specified + below. + + + + + + pkgs.formats.yaml { } + + + + A function taking an empty attribute set (for future + extensibility) and returning a set with YAML-specific + attributes type and + generate as specified + below. + + + + + + pkgs.formats.ini { + listsAsDuplicateKeys ? + false, listToValue ? + null, ... } + + + + A function taking an attribute set with values + + + + + listsAsDuplicateKeys + + + + A boolean for controlling whether list values can be + used to represent duplicate INI keys + + + + + + listToValue + + + + A function for turning a list of values into a single + value. + + + + + + It returns a set with INI-specific attributes + type and generate as + specified below. + + + + + + pkgs.formats.toml { } + + + + A function taking an empty attribute set (for future + extensibility) and returning a set with TOML-specific + attributes type and + generate as specified + below. + + + + + + These functions all return an attribute set with these values: + + + + + type + + + + A module system type representing a value of the format + + + + + + generate + filename jsonValue + + + + A function that can render a value of the format to a file. + Returns a file path. + + + + This function puts the value contents in the Nix store. So + this should be avoided for secrets. + + + + + + + + Example: Module with conventional + settings option + + + 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. + + +{ 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; }; + + # ... + }; +} + +
+ 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 + . + + + 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. + + + + Example: Declaring a type-checked + settings attribute + + +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. + ''; +}; + +
+
+