nixpkgs/nixos/modules/misc/documentation.nix
Arian van Putten 2e75a7b516 nixos: doc: optionally include all modules in manual generation
Before this change `man 5 configuration.nix` would only show options of modules in
the `baseModules` set, which consists only of the list of modules in
`nixos/modules/module-list.nix`

With this change applied and `documentation.nixos.includeAllModules` option enabled
all modules included in `configuration.nix` file will be used instead.

This makes configurations with custom modules self-documenting. It also means
that importing non-`baseModules` modules like `gce.nix` or `azure.nix`
will make their documentation available in `man 5 configuration.nix`.

`documentation.nixos.includeAllModules` is currently set to `false` by
default as enabling it usually uncovers bugs and prevents evaluation.
It should be set to `true` in a release or two.

This was originally implemented in #47177, edited for more configurability,
documented and rebased onto master by @oxij.
2019-03-05 09:41:40 +00:00

213 lines
7.3 KiB
Nix

{ config, lib, pkgs, baseModules, extraModules, modules, ... }:
with lib;
let
cfg = config.documentation;
manualModules = baseModules ++ optionals cfg.nixos.includeAllModules (extraModules ++ modules);
/* For the purpose of generating docs, evaluate options with each derivation
in `pkgs` (recursively) replaced by a fake with path "\${pkgs.attribute.path}".
It isn't perfect, but it seems to cover a vast majority of use cases.
Caveat: even if the package is reached by a different means,
the path above will be shown and not e.g. `${config.services.foo.package}`. */
manual = import ../../doc/manual rec {
inherit pkgs config;
version = config.system.nixos.release;
revision = "release-${version}";
options =
let
scrubbedEval = evalModules {
modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ manualModules;
args = (config._module.args) // { modules = [ ]; };
specialArgs = { pkgs = scrubDerivations "pkgs" pkgs; };
};
scrubDerivations = namePrefix: pkgSet: mapAttrs
(name: value:
let wholeName = "${namePrefix}.${name}"; in
if isAttrs value then
scrubDerivations wholeName value
// (optionalAttrs (isDerivation value) { outPath = "\${${wholeName}}"; })
else value
)
pkgSet;
in scrubbedEval.options;
};
helpScript = pkgs.writeScriptBin "nixos-help"
''
#! ${pkgs.runtimeShell} -e
# Finds first executable browser in a colon-separated list.
# (see how xdg-open defines BROWSER)
browser="$(
IFS=: ; for b in $BROWSER; do
[ -n "$(type -P "$b" || true)" ] && echo "$b" && break
done
)"
if [ -z "$browser" ]; then
browser="$(type -P xdg-open || true)"
if [ -z "$browser" ]; then
browser="$(type -P w3m || true)"
if [ -z "$browser" ]; then
echo "$0: unable to start a web browser; please set \$BROWSER"
exit 1
fi
fi
fi
exec "$browser" ${manual.manualHTMLIndex}
'';
desktopItem = pkgs.makeDesktopItem {
name = "nixos-manual";
desktopName = "NixOS Manual";
genericName = "View NixOS documentation in a web browser";
icon = "nix-snowflake";
exec = "${helpScript}/bin/nixos-help";
categories = "System";
};
in
{
options = {
documentation = {
enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install documentation of packages from
<option>environment.systemPackages</option> into the generated system path.
See "Multiple-output packages" chapter in the nixpkgs manual for more info.
'';
# which is at ../../../doc/multiple-output.xml
};
man.enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install manual pages and the <command>man</command> command.
This also includes "man" outputs.
'';
};
info.enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install info pages and the <command>info</command> command.
This also includes "info" outputs.
'';
};
doc.enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install documentation distributed in packages' <literal>/share/doc</literal>.
Usually plain text and/or HTML.
This also includes "doc" outputs.
'';
};
dev.enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to install documentation targeted at developers.
<itemizedlist>
<listitem><para>This includes man pages targeted at developers if <option>man.enable</option> is
set (this also includes "devman" outputs).</para></listitem>
<listitem><para>This includes info pages targeted at developers if <option>info.enable</option>
is set (this also includes "devinfo" outputs).</para></listitem>
<listitem><para>This includes other pages targeted at developers if <option>doc.enable</option>
is set (this also includes "devdoc" outputs).</para></listitem>
</itemizedlist>
'';
};
nixos.enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install NixOS's own documentation.
<itemizedlist>
<listitem><para>This includes man pages like
<citerefentry><refentrytitle>configuration.nix</refentrytitle>
<manvolnum>5</manvolnum></citerefentry> if <option>man.enable</option> is
set.</para></listitem>
<listitem><para>This includes the HTML manual and the <command>nixos-help</command> command if
<option>doc.enable</option> is set.</para></listitem>
</itemizedlist>
'';
};
nixos.includeAllModules = mkOption {
type = types.bool;
default = false;
description = ''
Whether the generated NixOS's documentation should include documentation for all
the options from all the NixOS modules included in the current
<literal>configuration.nix</literal>. Disabling this will make the manual
generator to ignore options defined outside of <literal>baseModules</literal>.
'';
};
};
};
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.man.enable {
environment.systemPackages = [ pkgs.man-db ];
environment.pathsToLink = [ "/share/man" ];
environment.extraOutputsToInstall = [ "man" ] ++ optional cfg.dev.enable "devman";
environment.etc."man.conf".source = "${pkgs.man-db}/etc/man_db.conf";
})
(mkIf cfg.info.enable {
environment.systemPackages = [ pkgs.texinfoInteractive ];
environment.pathsToLink = [ "/share/info" ];
environment.extraOutputsToInstall = [ "info" ] ++ optional cfg.dev.enable "devinfo";
environment.extraSetup = ''
if [ -w $out/share/info ]; then
shopt -s nullglob
for i in $out/share/info/*.info $out/share/info/*.info.gz; do
${pkgs.buildPackages.texinfo}/bin/install-info $i $out/share/info/dir
done
fi
'';
})
(mkIf cfg.doc.enable {
# TODO(@oxij): put it here and remove from profiles?
# environment.systemPackages = [ pkgs.w3m ]; # w3m-nox?
environment.pathsToLink = [ "/share/doc" ];
environment.extraOutputsToInstall = [ "doc" ] ++ optional cfg.dev.enable "devdoc";
})
(mkIf cfg.nixos.enable {
system.build.manual = manual;
environment.systemPackages = []
++ optional cfg.man.enable manual.manpages
++ optionals cfg.doc.enable ([ manual.manualHTML helpScript ]
++ optionals config.services.xserver.enable [ desktopItem pkgs.nixos-icons ]);
services.mingetty.helpLine = mkIf cfg.doc.enable (
"\nRun `nixos-help` "
+ optionalString config.services.nixosManual.showManual "or press <Alt-F${toString config.services.nixosManual.ttyNumber}> "
+ "for the NixOS manual."
);
})
]);
}