1{ config, lib, pkgs, baseModules, extraModules, modules, modulesPath, ... }:
2
3with lib;
4
5let
6
7 cfg = config.documentation;
8
9 manualModules =
10 baseModules
11 # Modules for which to show options even when not imported
12 ++ [ ../virtualisation/qemu-vm.nix ]
13 ++ optionals cfg.nixos.includeAllModules (extraModules ++ modules);
14
15 /* For the purpose of generating docs, evaluate options with each derivation
16 in `pkgs` (recursively) replaced by a fake with path "\${pkgs.attribute.path}".
17 It isn't perfect, but it seems to cover a vast majority of use cases.
18 Caveat: even if the package is reached by a different means,
19 the path above will be shown and not e.g. `${config.services.foo.package}`. */
20 manual = import ../../doc/manual rec {
21 inherit pkgs config;
22 version = config.system.nixos.release;
23 revision = "release-${version}";
24 extraSources = cfg.nixos.extraModuleSources;
25 options =
26 let
27 scrubbedEval = evalModules {
28 modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ manualModules;
29 args = (config._module.args) // { modules = [ ]; };
30 specialArgs = {
31 pkgs = scrubDerivations "pkgs" pkgs;
32 inherit modulesPath;
33 };
34 };
35 scrubDerivations = namePrefix: pkgSet: mapAttrs
36 (name: value:
37 let wholeName = "${namePrefix}.${name}"; in
38 if isAttrs value then
39 scrubDerivations wholeName value
40 // (optionalAttrs (isDerivation value) { outPath = "\${${wholeName}}"; })
41 else value
42 )
43 pkgSet;
44 in scrubbedEval.options;
45 };
46
47
48 nixos-help = let
49 helpScript = pkgs.writeShellScriptBin "nixos-help" ''
50 # Finds first executable browser in a colon-separated list.
51 # (see how xdg-open defines BROWSER)
52 browser="$(
53 IFS=: ; for b in $BROWSER; do
54 [ -n "$(type -P "$b" || true)" ] && echo "$b" && break
55 done
56 )"
57 if [ -z "$browser" ]; then
58 browser="$(type -P xdg-open || true)"
59 if [ -z "$browser" ]; then
60 browser="${pkgs.w3m-nographics}/bin/w3m"
61 fi
62 fi
63 exec "$browser" ${manual.manualHTMLIndex}
64 '';
65
66 desktopItem = pkgs.makeDesktopItem {
67 name = "nixos-manual";
68 desktopName = "NixOS Manual";
69 genericName = "View NixOS documentation in a web browser";
70 icon = "nix-snowflake";
71 exec = "nixos-help";
72 categories = "System";
73 };
74
75 in pkgs.symlinkJoin {
76 name = "nixos-help";
77 paths = [
78 helpScript
79 desktopItem
80 ];
81 };
82
83in
84
85{
86 imports = [
87 (mkRenamedOptionModule [ "programs" "info" "enable" ] [ "documentation" "info" "enable" ])
88 (mkRenamedOptionModule [ "programs" "man" "enable" ] [ "documentation" "man" "enable" ])
89 (mkRenamedOptionModule [ "services" "nixosManual" "enable" ] [ "documentation" "nixos" "enable" ])
90 ];
91
92 options = {
93
94 documentation = {
95
96 enable = mkOption {
97 type = types.bool;
98 default = true;
99 description = ''
100 Whether to install documentation of packages from
101 <option>environment.systemPackages</option> into the generated system path.
102
103 See "Multiple-output packages" chapter in the nixpkgs manual for more info.
104 '';
105 # which is at ../../../doc/multiple-output.chapter.md
106 };
107
108 man.enable = mkOption {
109 type = types.bool;
110 default = true;
111 description = ''
112 Whether to install manual pages and the <command>man</command> command.
113 This also includes "man" outputs.
114 '';
115 };
116
117 man.generateCaches = mkOption {
118 type = types.bool;
119 default = false;
120 description = ''
121 Whether to generate the manual page index caches using
122 <literal>mandb(8)</literal>. This allows searching for a page or
123 keyword using utilities like <literal>apropos(1)</literal>.
124 '';
125 };
126
127 man.manualPages = mkOption {
128 type = types.path;
129 default = pkgs.buildEnv {
130 name = "man-paths";
131 paths = config.environment.systemPackages;
132 pathsToLink = [ "/share/man" ];
133 extraOutputsToInstall = ["man"];
134 ignoreCollisions = true;
135 };
136 defaultText = literalDocBook "all man pages in <option>config.environment.systemPackages</option>";
137 description = ''
138 The manual pages to generate caches for if <option>generateCaches</option>
139 is enabled. Must be a path to a directory with man pages under
140 <literal>/share/man</literal>; see the source for an example.
141 Advanced users can make this a content-addressed derivation to save a few rebuilds.
142 '';
143 };
144
145 info.enable = mkOption {
146 type = types.bool;
147 default = true;
148 description = ''
149 Whether to install info pages and the <command>info</command> command.
150 This also includes "info" outputs.
151 '';
152 };
153
154 doc.enable = mkOption {
155 type = types.bool;
156 default = true;
157 description = ''
158 Whether to install documentation distributed in packages' <literal>/share/doc</literal>.
159 Usually plain text and/or HTML.
160 This also includes "doc" outputs.
161 '';
162 };
163
164 dev.enable = mkOption {
165 type = types.bool;
166 default = false;
167 description = ''
168 Whether to install documentation targeted at developers.
169 <itemizedlist>
170 <listitem><para>This includes man pages targeted at developers if <option>documentation.man.enable</option> is
171 set (this also includes "devman" outputs).</para></listitem>
172 <listitem><para>This includes info pages targeted at developers if <option>documentation.info.enable</option>
173 is set (this also includes "devinfo" outputs).</para></listitem>
174 <listitem><para>This includes other pages targeted at developers if <option>documentation.doc.enable</option>
175 is set (this also includes "devdoc" outputs).</para></listitem>
176 </itemizedlist>
177 '';
178 };
179
180 nixos.enable = mkOption {
181 type = types.bool;
182 default = true;
183 description = ''
184 Whether to install NixOS's own documentation.
185 <itemizedlist>
186 <listitem><para>This includes man pages like
187 <citerefentry><refentrytitle>configuration.nix</refentrytitle>
188 <manvolnum>5</manvolnum></citerefentry> if <option>documentation.man.enable</option> is
189 set.</para></listitem>
190 <listitem><para>This includes the HTML manual and the <command>nixos-help</command> command if
191 <option>documentation.doc.enable</option> is set.</para></listitem>
192 </itemizedlist>
193 '';
194 };
195
196 nixos.includeAllModules = mkOption {
197 type = types.bool;
198 default = false;
199 description = ''
200 Whether the generated NixOS's documentation should include documentation for all
201 the options from all the NixOS modules included in the current
202 <literal>configuration.nix</literal>. Disabling this will make the manual
203 generator to ignore options defined outside of <literal>baseModules</literal>.
204 '';
205 };
206
207 nixos.extraModuleSources = mkOption {
208 type = types.listOf (types.either types.path types.str);
209 default = [ ];
210 description = ''
211 Which extra NixOS module paths the generated NixOS's documentation should strip
212 from options.
213 '';
214 example = literalExpression ''
215 # e.g. with options from modules in ''${pkgs.customModules}/nix:
216 [ pkgs.customModules ]
217 '';
218 };
219
220 };
221
222 };
223
224 config = mkIf cfg.enable (mkMerge [
225
226 (mkIf cfg.man.enable {
227 environment.systemPackages = [ pkgs.man-db ];
228 environment.pathsToLink = [ "/share/man" ];
229 environment.extraOutputsToInstall = [ "man" ] ++ optional cfg.dev.enable "devman";
230 environment.etc."man_db.conf".text =
231 let
232 manualCache = pkgs.runCommandLocal "man-cache" { } ''
233 echo "MANDB_MAP ${cfg.man.manualPages}/share/man $out" > man.conf
234 ${pkgs.man-db}/bin/mandb -C man.conf -psc >/dev/null 2>&1
235 '';
236 in
237 ''
238 # Manual pages paths for NixOS
239 MANPATH_MAP /run/current-system/sw/bin /run/current-system/sw/share/man
240 MANPATH_MAP /run/wrappers/bin /run/current-system/sw/share/man
241
242 ${optionalString cfg.man.generateCaches ''
243 # Generated manual pages cache for NixOS (immutable)
244 MANDB_MAP /run/current-system/sw/share/man ${manualCache}
245 ''}
246 # Manual pages caches for NixOS
247 MANDB_MAP /run/current-system/sw/share/man /var/cache/man/nixos
248 '';
249 })
250
251 (mkIf cfg.info.enable {
252 environment.systemPackages = [ pkgs.texinfoInteractive ];
253 environment.pathsToLink = [ "/share/info" ];
254 environment.extraOutputsToInstall = [ "info" ] ++ optional cfg.dev.enable "devinfo";
255 environment.extraSetup = ''
256 if [ -w $out/share/info ]; then
257 shopt -s nullglob
258 for i in $out/share/info/*.info $out/share/info/*.info.gz; do
259 ${pkgs.buildPackages.texinfo}/bin/install-info $i $out/share/info/dir
260 done
261 fi
262 '';
263 })
264
265 (mkIf cfg.doc.enable {
266 environment.pathsToLink = [ "/share/doc" ];
267 environment.extraOutputsToInstall = [ "doc" ] ++ optional cfg.dev.enable "devdoc";
268 })
269
270 (mkIf cfg.nixos.enable {
271 system.build.manual = manual;
272
273 environment.systemPackages = []
274 ++ optional cfg.man.enable manual.manpages
275 ++ optionals cfg.doc.enable [ manual.manualHTML nixos-help ];
276
277 services.getty.helpLine = mkIf cfg.doc.enable (
278 "\nRun 'nixos-help' for the NixOS manual."
279 );
280 })
281
282 ]);
283
284}