Merge pull request #329823 from ExpidusOS/fix/pkgsllvm/elfutils
[NixPkgs.git] / nixos / modules / misc / documentation.nix
blob26323e14b9017ddc3f7fcb7873286a3bcc9600f2
1 { config, options, lib, pkgs, utils, modules, baseModules, extraModules, modulesPath, specialArgs, ... }:
3 let
4   inherit (lib)
5     cleanSourceFilter
6     concatMapStringsSep
7     evalModules
8     filter
9     functionArgs
10     hasSuffix
11     isAttrs
12     isDerivation
13     isFunction
14     isPath
15     literalExpression
16     mapAttrs
17     mkIf
18     mkMerge
19     mkOption
20     mkRemovedOptionModule
21     mkRenamedOptionModule
22     optional
23     optionalAttrs
24     optionals
25     partition
26     removePrefix
27     types
28     warn
29     ;
31   cfg = config.documentation;
32   allOpts = options;
34   canCacheDocs = m:
35     let
36       f = import m;
37       instance = f (mapAttrs (n: _: abort "evaluating ${n} for `meta` failed") (functionArgs f));
38     in
39       cfg.nixos.options.splitBuild
40         && isPath m
41         && isFunction f
42         && instance ? options
43         && instance.meta.buildDocsInSandbox or true;
45   docModules =
46     let
47       p = partition canCacheDocs (baseModules ++ cfg.nixos.extraModules);
48     in
49       {
50         lazy = p.right;
51         eager = p.wrong ++ optionals cfg.nixos.includeAllModules (extraModules ++ modules);
52       };
54   manual = import ../../doc/manual rec {
55     inherit pkgs config;
56     version = config.system.nixos.release;
57     revision = "release-${version}";
58     extraSources = cfg.nixos.extraModuleSources;
59     options =
60       let
61         scrubbedEval = evalModules {
62           modules = [ {
63             _module.check = false;
64           } ] ++ docModules.eager;
65           class = "nixos";
66           specialArgs = specialArgs // {
67             pkgs = scrubDerivations "pkgs" pkgs;
68             # allow access to arbitrary options for eager modules, eg for getting
69             # option types from lazy modules
70             options = allOpts;
71             inherit modulesPath utils;
72           };
73         };
74         scrubDerivations = namePrefix: pkgSet: mapAttrs
75           (name: value:
76             let
77               wholeName = "${namePrefix}.${name}";
78               guard = warn "Attempt to evaluate package ${wholeName} in option documentation; this is not supported and will eventually be an error. Use `mkPackageOption{,MD}` or `literalExpression` instead.";
79             in if isAttrs value then
80               scrubDerivations wholeName value
81               // optionalAttrs (isDerivation value) {
82                 outPath = guard "\${${wholeName}}";
83                 drvPath = guard value.drvPath;
84               }
85             else value
86           )
87           pkgSet;
88       in scrubbedEval.options;
90     baseOptionsJSON =
91       let
92         filter =
93           builtins.filterSource
94             (n: t:
95               cleanSourceFilter n t
96               && (t == "directory" -> baseNameOf n != "tests")
97               && (t == "file" -> hasSuffix ".nix" n)
98             );
99       in
100         pkgs.runCommand "lazy-options.json" {
101           libPath = filter (pkgs.path + "/lib");
102           pkgsLibPath = filter (pkgs.path + "/pkgs/pkgs-lib");
103           nixosPath = filter (pkgs.path + "/nixos");
104           NIX_ABORT_ON_WARN = warningsAreErrors;
105           modules =
106             "[ "
107             + concatMapStringsSep " " (p: ''"${removePrefix "${modulesPath}/" (toString p)}"'') docModules.lazy
108             + " ]";
109           passAsFile = [ "modules" ];
110         } ''
111           export NIX_STORE_DIR=$TMPDIR/store
112           export NIX_STATE_DIR=$TMPDIR/state
113           ${pkgs.buildPackages.nix}/bin/nix-instantiate \
114             --show-trace \
115             --eval --json --strict \
116             --argstr libPath "$libPath" \
117             --argstr pkgsLibPath "$pkgsLibPath" \
118             --argstr nixosPath "$nixosPath" \
119             --arg modules "import $modulesPath" \
120             --argstr stateVersion "${options.system.stateVersion.default}" \
121             --argstr release "${config.system.nixos.release}" \
122             $nixosPath/lib/eval-cacheable-options.nix > $out \
123             || {
124               echo -en "\e[1;31m"
125               echo 'Cacheable portion of option doc build failed.'
126               echo 'Usually this means that an option attribute that ends up in documentation (eg' \
127                 '`default` or `description`) depends on the restricted module arguments' \
128                 '`config` or `pkgs`.'
129               echo
130               echo 'Rebuild your configuration with `--show-trace` to find the offending' \
131                 'location. Remove the references to restricted arguments (eg by escaping' \
132                 'their antiquotations or adding a `defaultText`) or disable the sandboxed' \
133                 'build for the failing module by setting `meta.buildDocsInSandbox = false`.'
134               echo -en "\e[0m"
135               exit 1
136             } >&2
137         '';
139     inherit (cfg.nixos.options) warningsAreErrors;
140   };
143   nixos-help = let
144     helpScript = pkgs.writeShellScriptBin "nixos-help" ''
145       # Finds first executable browser in a colon-separated list.
146       # (see how xdg-open defines BROWSER)
147       browser="$(
148         IFS=: ; for b in $BROWSER; do
149           [ -n "$(type -P "$b" || true)" ] && echo "$b" && break
150         done
151       )"
152       if [ -z "$browser" ]; then
153         browser="$(type -P xdg-open || true)"
154         if [ -z "$browser" ]; then
155           browser="${pkgs.w3m-nographics}/bin/w3m"
156         fi
157       fi
158       exec "$browser" ${manual.manualHTMLIndex}
159     '';
161     desktopItem = pkgs.makeDesktopItem {
162       name = "nixos-manual";
163       desktopName = "NixOS Manual";
164       genericName = "System Manual";
165       comment = "View NixOS documentation in a web browser";
166       icon = "nix-snowflake";
167       exec = "nixos-help";
168       categories = ["System"];
169     };
171     in pkgs.symlinkJoin {
172       name = "nixos-help";
173       paths = [
174         helpScript
175         desktopItem
176       ];
177     };
182   imports = [
183     ./man-db.nix
184     ./mandoc.nix
185     ./assertions.nix
186     ./meta.nix
187     ../config/system-path.nix
188     ../system/etc/etc.nix
189     (mkRenamedOptionModule [ "programs" "info" "enable" ] [ "documentation" "info" "enable" ])
190     (mkRenamedOptionModule [ "programs" "man"  "enable" ] [ "documentation" "man"  "enable" ])
191     (mkRenamedOptionModule [ "services" "nixosManual" "enable" ] [ "documentation" "nixos" "enable" ])
192     (mkRemovedOptionModule
193       [ "documentation" "nixos" "options" "allowDocBook" ]
194       "DocBook option documentation is no longer supported")
195   ];
197   options = {
199     documentation = {
201       enable = mkOption {
202         type = types.bool;
203         default = true;
204         description = ''
205           Whether to install documentation of packages from
206           {option}`environment.systemPackages` into the generated system path.
208           See "Multiple-output packages" chapter in the nixpkgs manual for more info.
209         '';
210         # which is at ../../../doc/multiple-output.chapter.md
211       };
213       man.enable = mkOption {
214         type = types.bool;
215         default = true;
216         description = ''
217           Whether to install manual pages.
218           This also includes `man` outputs.
219         '';
220       };
222       man.generateCaches = mkOption {
223         type = types.bool;
224         default = false;
225         description = ''
226           Whether to generate the manual page index caches.
227           This allows searching for a page or
228           keyword using utilities like {manpage}`apropos(1)`
229           and the `-k` option of
230           {manpage}`man(1)`.
231         '';
232       };
234       info.enable = mkOption {
235         type = types.bool;
236         default = true;
237         description = ''
238           Whether to install info pages and the {command}`info` command.
239           This also includes "info" outputs.
240         '';
241       };
243       doc.enable = mkOption {
244         type = types.bool;
245         default = true;
246         description = ''
247           Whether to install documentation distributed in packages' `/share/doc`.
248           Usually plain text and/or HTML.
249           This also includes "doc" outputs.
250         '';
251       };
253       dev.enable = mkOption {
254         type = types.bool;
255         default = false;
256         description = ''
257           Whether to install documentation targeted at developers.
258           * This includes man pages targeted at developers if {option}`documentation.man.enable` is
259             set (this also includes "devman" outputs).
260           * This includes info pages targeted at developers if {option}`documentation.info.enable`
261             is set (this also includes "devinfo" outputs).
262           * This includes other pages targeted at developers if {option}`documentation.doc.enable`
263             is set (this also includes "devdoc" outputs).
264         '';
265       };
267       nixos.enable = mkOption {
268         type = types.bool;
269         default = true;
270         description = ''
271           Whether to install NixOS's own documentation.
273           - This includes man pages like
274             {manpage}`configuration.nix(5)` if {option}`documentation.man.enable` is
275             set.
276           - This includes the HTML manual and the {command}`nixos-help` command if
277             {option}`documentation.doc.enable` is set.
278         '';
279       };
281       nixos.extraModules = mkOption {
282         type = types.listOf types.raw;
283         default = [];
284         description = ''
285           Modules for which to show options even when not imported.
286         '';
287       };
289       nixos.options.splitBuild = mkOption {
290         type = types.bool;
291         default = true;
292         description = ''
293           Whether to split the option docs build into a cacheable and an uncacheable part.
294           Splitting the build can substantially decrease the amount of time needed to build
295           the manual, but some user modules may be incompatible with this splitting.
296         '';
297       };
299       nixos.options.warningsAreErrors = mkOption {
300         type = types.bool;
301         default = true;
302         description = ''
303           Treat warning emitted during the option documentation build (eg for missing option
304           descriptions) as errors.
305         '';
306       };
308       nixos.includeAllModules = mkOption {
309         type = types.bool;
310         default = false;
311         description = ''
312           Whether the generated NixOS's documentation should include documentation for all
313           the options from all the NixOS modules included in the current
314           `configuration.nix`. Disabling this will make the manual
315           generator to ignore options defined outside of `baseModules`.
316         '';
317       };
319       nixos.extraModuleSources = mkOption {
320         type = types.listOf (types.either types.path types.str);
321         default = [ ];
322         description = ''
323           Which extra NixOS module paths the generated NixOS's documentation should strip
324           from options.
325         '';
326         example = literalExpression ''
327           # e.g. with options from modules in ''${pkgs.customModules}/nix:
328           [ pkgs.customModules ]
329         '';
330       };
332     };
334   };
336   config = mkIf cfg.enable (mkMerge [
337     {
338       assertions = [
339         {
340           assertion = !(cfg.man.man-db.enable && cfg.man.mandoc.enable);
341           message = ''
342             man-db and mandoc can't be used as the default man page viewer at the same time!
343           '';
344         }
345       ];
346     }
348     # The actual implementation for this lives in man-db.nix or mandoc.nix,
349     # depending on which backend is active.
350     (mkIf cfg.man.enable {
351       environment.pathsToLink = [ "/share/man" ];
352       environment.extraOutputsToInstall = [ "man" ] ++ optional cfg.dev.enable "devman";
353     })
355     (mkIf cfg.info.enable {
356       environment.systemPackages = [ pkgs.texinfoInteractive ];
357       environment.pathsToLink = [ "/share/info" ];
358       environment.extraOutputsToInstall = [ "info" ] ++ optional cfg.dev.enable "devinfo";
359       environment.extraSetup = ''
360         if [ -w $out/share/info ]; then
361           shopt -s nullglob
362           for i in $out/share/info/*.info $out/share/info/*.info.gz; do
363               ${pkgs.buildPackages.texinfo}/bin/install-info $i $out/share/info/dir
364           done
365         fi
366       '';
367     })
369     (mkIf cfg.doc.enable {
370       environment.pathsToLink = [ "/share/doc" ];
371       environment.extraOutputsToInstall = [ "doc" ] ++ optional cfg.dev.enable "devdoc";
372     })
374     (mkIf cfg.nixos.enable {
375       system.build.manual = manual;
377       environment.systemPackages = []
378         ++ optional cfg.man.enable manual.nixos-configuration-reference-manpage
379         ++ optionals cfg.doc.enable [ manual.manualHTML nixos-help ];
380     })
382   ]);