1{ pkgs
2, options
3, config
4, version
5, revision
6, extraSources ? []
7, baseOptionsJSON ? null
8, warningsAreErrors ? true
9, allowDocBook ? true
10, prefix ? ../../..
11}:
12
13with pkgs;
14
15let
16 inherit (lib) hasPrefix removePrefix;
17
18 lib = pkgs.lib;
19
20 docbook_xsl_ns = pkgs.docbook-xsl-ns.override {
21 withManOptDedupPatch = true;
22 };
23
24 manpageUrls = pkgs.path + "/doc/manpage-urls.json";
25
26 # We need to strip references to /nix/store/* from options,
27 # including any `extraSources` if some modules came from elsewhere,
28 # or else the build will fail.
29 #
30 # E.g. if some `options` came from modules in ${pkgs.customModules}/nix,
31 # you'd need to include `extraSources = [ pkgs.customModules ]`
32 prefixesToStrip = map (p: "${toString p}/") ([ prefix ] ++ extraSources);
33 stripAnyPrefixes = lib.flip (lib.foldr lib.removePrefix) prefixesToStrip;
34
35 optionsDoc = buildPackages.nixosOptionsDoc {
36 inherit options revision baseOptionsJSON warningsAreErrors allowDocBook;
37 transformOptions = opt: opt // {
38 # Clean up declaration sites to not refer to the NixOS source tree.
39 declarations = map stripAnyPrefixes opt.declarations;
40 };
41 };
42
43 nixos-lib = import ../../lib { };
44
45 testOptionsDoc = let
46 eval = nixos-lib.evalTest {
47 # Avoid evaluating a NixOS config prototype.
48 config.node.type = lib.types.deferredModule;
49 options._module.args = lib.mkOption { internal = true; };
50 };
51 in buildPackages.nixosOptionsDoc {
52 inherit (eval) options;
53 inherit revision;
54 transformOptions = opt: opt // {
55 # Clean up declaration sites to not refer to the NixOS source tree.
56 declarations =
57 map
58 (decl:
59 if hasPrefix (toString ../../..) (toString decl)
60 then
61 let subpath = removePrefix "/" (removePrefix (toString ../../..) (toString decl));
62 in { url = "https://github.com/NixOS/nixpkgs/blob/master/${subpath}"; name = subpath; }
63 else decl)
64 opt.declarations;
65 };
66 documentType = "none";
67 variablelistId = "test-options-list";
68 optionIdPrefix = "test-opt-";
69 };
70
71 toc = builtins.toFile "toc.xml"
72 ''
73 <toc role="chunk-toc">
74 <d:tocentry xmlns:d="http://docbook.org/ns/docbook" linkend="book-nixos-manual"><?dbhtml filename="index.html"?>
75 <d:tocentry linkend="ch-options"><?dbhtml filename="options.html"?></d:tocentry>
76 <d:tocentry linkend="ch-release-notes"><?dbhtml filename="release-notes.html"?></d:tocentry>
77 </d:tocentry>
78 </toc>
79 '';
80
81 manualXsltprocOptions = toString [
82 "--param chapter.autolabel 0"
83 "--param part.autolabel 0"
84 "--param preface.autolabel 0"
85 "--param reference.autolabel 0"
86 "--param section.autolabel 0"
87 "--stringparam html.stylesheet 'style.css overrides.css highlightjs/mono-blue.css'"
88 "--stringparam html.script './highlightjs/highlight.pack.js ./highlightjs/loader.js'"
89 "--param xref.with.number.and.title 0"
90 "--param toc.section.depth 0"
91 "--param generate.consistent.ids 1"
92 "--stringparam admon.style ''"
93 "--stringparam callout.graphics.extension .svg"
94 "--stringparam current.docid manual"
95 "--param chunk.section.depth 0"
96 "--param chunk.first.sections 1"
97 "--param use.id.as.filename 1"
98 "--stringparam chunk.toc ${toc}"
99 ];
100
101 linterFunctions = ''
102 # outputs the context of an xmllint error output
103 # LEN lines around the failing line are printed
104 function context {
105 # length of context
106 local LEN=6
107 # lines to print before error line
108 local BEFORE=4
109
110 # xmllint output lines are:
111 # file.xml:1234: there was an error on line 1234
112 while IFS=':' read -r file line rest; do
113 echo
114 if [[ -n "$rest" ]]; then
115 echo "$file:$line:$rest"
116 local FROM=$(($line>$BEFORE ? $line - $BEFORE : 1))
117 # number lines & filter context
118 nl --body-numbering=a "$file" | sed -n "$FROM,+$LEN p"
119 else
120 if [[ -n "$line" ]]; then
121 echo "$file:$line"
122 else
123 echo "$file"
124 fi
125 fi
126 done
127 }
128
129 function lintrng {
130 xmllint --debug --noout --nonet \
131 --relaxng ${docbook5}/xml/rng/docbook/docbook.rng \
132 "$1" \
133 2>&1 | context 1>&2
134 # ^ redirect assumes xmllint doesn’t print to stdout
135 }
136 '';
137
138 prepareManualFromMD = ''
139 cp -r --no-preserve=all $inputs/* .
140
141 substituteInPlace ./manual.md \
142 --replace '@NIXOS_VERSION@' "${version}"
143 substituteInPlace ./configuration/configuration.md \
144 --replace \
145 '@MODULE_CHAPTERS@' \
146 ${lib.escapeShellArg (lib.concatMapStringsSep "\n" (p: "${p.value}") config.meta.doc)}
147 substituteInPlace ./nixos-options.md \
148 --replace \
149 '@NIXOS_OPTIONS_JSON@' \
150 ${optionsDoc.optionsJSON}/share/doc/nixos/options.json
151 substituteInPlace ./development/writing-nixos-tests.section.md \
152 --replace \
153 '@NIXOS_TEST_OPTIONS_JSON@' \
154 ${testOptionsDoc.optionsJSON}/share/doc/nixos/options.json
155 '';
156
157 manual-combined = runCommand "nixos-manual-combined"
158 { inputs = lib.sourceFilesBySuffices ./. [ ".xml" ".md" ];
159 nativeBuildInputs = [ pkgs.nixos-render-docs pkgs.libxml2.bin pkgs.libxslt.bin ];
160 meta.description = "The NixOS manual as plain docbook XML";
161 }
162 ''
163 ${prepareManualFromMD}
164
165 nixos-render-docs -j $NIX_BUILD_CORES manual docbook \
166 --manpage-urls ${manpageUrls} \
167 --revision ${lib.escapeShellArg revision} \
168 ./manual.md \
169 ./manual-combined-pre.xml
170
171 xsltproc \
172 -o manual-combined.xml ${./../../lib/make-options-doc/postprocess-option-descriptions.xsl} \
173 manual-combined-pre.xml
174
175 ${linterFunctions}
176
177 mkdir $out
178 cp manual-combined.xml $out/
179
180 lintrng $out/manual-combined.xml
181 '';
182
183 manpages-combined = runCommand "nixos-manpages-combined.xml"
184 { nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
185 meta.description = "The NixOS manpages as plain docbook XML";
186 }
187 ''
188 mkdir generated
189 cp -prd ${./man-pages.xml} man-pages.xml
190 ln -s ${optionsDoc.optionsDocBook} generated/options-db.xml
191
192 xmllint --xinclude --noxincludenode --output $out ./man-pages.xml
193
194 ${linterFunctions}
195
196 lintrng $out
197 '';
198
199in rec {
200 inherit (optionsDoc) optionsJSON optionsNix optionsDocBook optionsUsedDocbook;
201
202 # Generate the NixOS manual.
203 manualHTML = runCommand "nixos-manual-html"
204 { nativeBuildInputs =
205 if allowDocBook then [
206 buildPackages.libxml2.bin
207 buildPackages.libxslt.bin
208 ] else [
209 buildPackages.nixos-render-docs
210 ];
211 inputs = lib.optionals (! allowDocBook) (lib.sourceFilesBySuffices ./. [ ".md" ]);
212 meta.description = "The NixOS manual in HTML format";
213 allowedReferences = ["out"];
214 }
215 ''
216 # Generate the HTML manual.
217 dst=$out/share/doc/nixos
218 mkdir -p $dst
219
220 cp ${../../../doc/style.css} $dst/style.css
221 cp ${../../../doc/overrides.css} $dst/overrides.css
222 cp -r ${pkgs.documentation-highlighter} $dst/highlightjs
223
224 ${if allowDocBook then ''
225 xsltproc \
226 ${manualXsltprocOptions} \
227 --stringparam id.warnings "1" \
228 --nonet --output $dst/ \
229 ${docbook_xsl_ns}/xml/xsl/docbook/xhtml/chunktoc.xsl \
230 ${manual-combined}/manual-combined.xml \
231 |& tee xsltproc.out
232 grep "^ID recommended on" xsltproc.out &>/dev/null && echo "error: some IDs are missing" && false
233 rm xsltproc.out
234
235 mkdir -p $dst/images/callouts
236 cp ${docbook_xsl_ns}/xml/xsl/docbook/images/callouts/*.svg $dst/images/callouts/
237 '' else ''
238 ${prepareManualFromMD}
239
240 # TODO generator is set like this because the docbook/md manual compare workflow will
241 # trigger if it's different
242 nixos-render-docs -j $NIX_BUILD_CORES manual html \
243 --manpage-urls ${manpageUrls} \
244 --revision ${lib.escapeShellArg revision} \
245 --generator "DocBook XSL Stylesheets V${docbook_xsl_ns.version}" \
246 --stylesheet style.css \
247 --stylesheet overrides.css \
248 --stylesheet highlightjs/mono-blue.css \
249 --script ./highlightjs/highlight.pack.js \
250 --script ./highlightjs/loader.js \
251 --toc-depth 1 \
252 --chunk-toc-depth 1 \
253 ./manual.md \
254 $dst/index.html
255 ''}
256
257 mkdir -p $out/nix-support
258 echo "nix-build out $out" >> $out/nix-support/hydra-build-products
259 echo "doc manual $dst" >> $out/nix-support/hydra-build-products
260 ''; # */
261
262 # Alias for backward compatibility. TODO(@oxij): remove eventually.
263 manual = manualHTML;
264
265 # Index page of the NixOS manual.
266 manualHTMLIndex = "${manualHTML}/share/doc/nixos/index.html";
267
268 manualEpub = runCommand "nixos-manual-epub"
269 { nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin buildPackages.zip ];
270 }
271 ''
272 # Generate the epub manual.
273 dst=$out/share/doc/nixos
274
275 xsltproc \
276 ${manualXsltprocOptions} \
277 --nonet --xinclude --output $dst/epub/ \
278 ${docbook_xsl_ns}/xml/xsl/docbook/epub/docbook.xsl \
279 ${manual-combined}/manual-combined.xml
280
281 mkdir -p $dst/epub/OEBPS/images/callouts
282 cp -r ${docbook_xsl_ns}/xml/xsl/docbook/images/callouts/*.svg $dst/epub/OEBPS/images/callouts # */
283 echo "application/epub+zip" > mimetype
284 manual="$dst/nixos-manual.epub"
285 zip -0Xq "$manual" mimetype
286 cd $dst/epub && zip -Xr9D "$manual" *
287
288 rm -rf $dst/epub
289
290 mkdir -p $out/nix-support
291 echo "doc-epub manual $manual" >> $out/nix-support/hydra-build-products
292 '';
293
294
295 # Generate the NixOS manpages.
296 manpages = runCommand "nixos-manpages"
297 { nativeBuildInputs = [
298 buildPackages.installShellFiles
299 ] ++ lib.optionals allowDocBook [
300 buildPackages.libxml2.bin
301 buildPackages.libxslt.bin
302 ] ++ lib.optionals (! allowDocBook) [
303 buildPackages.nixos-render-docs
304 ];
305 allowedReferences = ["out"];
306 }
307 ''
308 # Generate manpages.
309 mkdir -p $out/share/man/man8
310 installManPage ${./manpages}/*
311 ${if allowDocBook
312 then ''
313 xsltproc --nonet \
314 --maxdepth 6000 \
315 --param man.output.in.separate.dir 1 \
316 --param man.output.base.dir "'$out/share/man/'" \
317 --param man.endnotes.are.numbered 0 \
318 --param man.break.after.slash 1 \
319 ${docbook_xsl_ns}/xml/xsl/docbook/manpages/docbook.xsl \
320 ${manpages-combined}
321 ''
322 else ''
323 mkdir -p $out/share/man/man5
324 nixos-render-docs -j $NIX_BUILD_CORES options manpage \
325 --revision ${lib.escapeShellArg revision} \
326 ${optionsJSON}/share/doc/nixos/options.json \
327 $out/share/man/man5/configuration.nix.5
328 ''}
329 '';
330
331}