1/* Generate JSON, XML and DocBook documentation for given NixOS options.
2
3 Minimal example:
4
5 { pkgs, }:
6
7 let
8 eval = import (pkgs.path + "/nixos/lib/eval-config.nix") {
9 baseModules = [
10 ../module.nix
11 ];
12 modules = [];
13 };
14 in pkgs.nixosOptionsDoc {
15 options = eval.options;
16 }
17
18*/
19{ pkgs
20, lib
21, options
22, transformOptions ? lib.id # function for additional transformations of the options
23, documentType ? "appendix" # TODO deprecate "appendix" in favor of "none"
24 # and/or rename function to moduleOptionDoc for clean slate
25
26 # If you include more than one option list into a document, you need to
27 # provide different ids.
28, variablelistId ? "configuration-variable-list"
29 # String to prefix to the option XML/HTML id attributes.
30, optionIdPrefix ? "opt-"
31, revision ? "" # Specify revision for the options
32# a set of options the docs we are generating will be merged into, as if by recursiveUpdate.
33# used to split the options doc build into a static part (nixos/modules) and a dynamic part
34# (non-nixos modules imported via configuration.nix, other module sources).
35, baseOptionsJSON ? null
36# instead of printing warnings for eg options with missing descriptions (which may be lost
37# by nix build unless -L is given), emit errors instead and fail the build
38, warningsAreErrors ? true
39# allow docbook option docs if `true`. only markdown documentation is allowed when set to
40# `false`, and a different renderer may be used with different bugs and performance
41# characteristics but (hopefully) indistinguishable output.
42, allowDocBook ? true
43# whether lib.mdDoc is required for descriptions to be read as markdown.
44# !!! when this is eventually flipped to true, `lib.doRename` should also default to emitting Markdown
45, markdownByDefault ? false
46}:
47
48let
49 rawOpts = lib.optionAttrSetToDocList options;
50 transformedOpts = map transformOptions rawOpts;
51 filteredOpts = lib.filter (opt: opt.visible && !opt.internal) transformedOpts;
52 optionsList = lib.flip map filteredOpts
53 (opt: opt
54 // lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages opt.name; }
55 );
56
57 # Generate DocBook documentation for a list of packages. This is
58 # what `relatedPackages` option of `mkOption` from
59 # ../../../lib/options.nix influences.
60 #
61 # Each element of `relatedPackages` can be either
62 # - a string: that will be interpreted as an attribute name from `pkgs` and turned into a link
63 # to search.nixos.org,
64 # - a list: that will be interpreted as an attribute path from `pkgs` and turned into a link
65 # to search.nixos.org,
66 # - an attrset: that can specify `name`, `path`, `comment`
67 # (either of `name`, `path` is required, the rest are optional).
68 #
69 # NOTE: No checks against `pkgs` are made to ensure that the referenced package actually exists.
70 # Such checks are not compatible with option docs caching.
71 genRelatedPackages = packages: optName:
72 let
73 unpack = p: if lib.isString p then { name = p; }
74 else if lib.isList p then { path = p; }
75 else p;
76 describe = args:
77 let
78 title = args.title or null;
79 name = args.name or (lib.concatStringsSep "." args.path);
80 in ''
81 - [${lib.optionalString (title != null) "${title} aka "}`pkgs.${name}`](
82 https://search.nixos.org/packages?show=${name}&sort=relevance&query=${name}
83 )${
84 lib.optionalString (args ? comment) "\n\n ${args.comment}"
85 }
86 '';
87 in lib.concatMapStrings (p: describe (unpack p)) packages;
88
89 optionsNix = builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList);
90
91in rec {
92 inherit optionsNix;
93
94 optionsAsciiDoc = pkgs.runCommand "options.adoc" {
95 nativeBuildInputs = [ pkgs.nixos-render-docs ];
96 } ''
97 nixos-render-docs -j $NIX_BUILD_CORES options asciidoc \
98 --manpage-urls ${pkgs.path + "/doc/manpage-urls.json"} \
99 --revision ${lib.escapeShellArg revision} \
100 ${optionsJSON}/share/doc/nixos/options.json \
101 $out
102 '';
103
104 optionsCommonMark = pkgs.runCommand "options.md" {
105 nativeBuildInputs = [ pkgs.nixos-render-docs ];
106 } ''
107 nixos-render-docs -j $NIX_BUILD_CORES options commonmark \
108 --manpage-urls ${pkgs.path + "/doc/manpage-urls.json"} \
109 --revision ${lib.escapeShellArg revision} \
110 ${optionsJSON}/share/doc/nixos/options.json \
111 $out
112 '';
113
114 optionsJSON = pkgs.runCommand "options.json"
115 { meta.description = "List of NixOS options in JSON format";
116 nativeBuildInputs = [
117 pkgs.brotli
118 pkgs.python3Minimal
119 ];
120 options = builtins.toFile "options.json"
121 (builtins.unsafeDiscardStringContext (builtins.toJSON optionsNix));
122 # merge with an empty set if baseOptionsJSON is null to run markdown
123 # processing on the input options
124 baseJSON =
125 if baseOptionsJSON == null
126 then builtins.toFile "base.json" "{}"
127 else baseOptionsJSON;
128 }
129 ''
130 # Export list of options in different format.
131 dst=$out/share/doc/nixos
132 mkdir -p $dst
133
134 TOUCH_IF_DB=$dst/.used-docbook \
135 python ${./mergeJSON.py} \
136 ${lib.optionalString warningsAreErrors "--warnings-are-errors"} \
137 ${if allowDocBook then "--warn-on-docbook" else "--error-on-docbook"} \
138 $baseJSON $options \
139 > $dst/options.json
140
141 brotli -9 < $dst/options.json > $dst/options.json.br
142
143 mkdir -p $out/nix-support
144 echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products
145 echo "file json-br $dst/options.json.br" >> $out/nix-support/hydra-build-products
146 '';
147
148 optionsUsedDocbook = pkgs.runCommand "options-used-docbook" {} ''
149 if [ -e ${optionsJSON}/share/doc/nixos/.used-docbook ]; then
150 echo 1
151 else
152 echo 0
153 fi >"$out"
154 '';
155
156 optionsDocBook = pkgs.runCommand "options-docbook.xml" {
157 nativeBuildInputs = [
158 pkgs.nixos-render-docs
159 ];
160 } ''
161 nixos-render-docs -j $NIX_BUILD_CORES options docbook \
162 --manpage-urls ${pkgs.path + "/doc/manpage-urls.json"} \
163 --revision ${lib.escapeShellArg revision} \
164 --document-type ${lib.escapeShellArg documentType} \
165 --varlist-id ${lib.escapeShellArg variablelistId} \
166 --id-prefix ${lib.escapeShellArg optionIdPrefix} \
167 ${lib.optionalString markdownByDefault "--markdown-by-default"} \
168 ${optionsJSON}/share/doc/nixos/options.json \
169 options.xml
170
171 if grep /nixpkgs/nixos/modules options.xml; then
172 echo "The manual appears to depend on the location of Nixpkgs, which is bad"
173 echo "since this prevents sharing via the NixOS channel. This is typically"
174 echo "caused by an option default that refers to a relative path (see above"
175 echo "for hints about the offending path)."
176 exit 1
177 fi
178
179 ${pkgs.libxslt.bin}/bin/xsltproc \
180 -o "$out" ${./postprocess-option-descriptions.xsl} options.xml
181 '';
182}