Extract NixOS options documentation generation to a function

Motivation is to support other repositories containing nixos
modules that would like to generate options documentation:

- nix-darwin
- private repos
- arion
- ??

Changed files
+138 -97
nixos
pkgs
top-level
+9 -97
nixos/doc/manual/default.nix
···
let
lib = pkgs.lib;
-
# Remove invisible and internal options.
-
optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options);
-
-
# Replace functions by the string <function>
-
substFunction = x:
-
if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x
-
else if builtins.isList x then map substFunction x
-
else if lib.isFunction x then "<function>"
-
else x;
-
-
# Generate DocBook documentation for a list of packages. This is
-
# what `relatedPackages` option of `mkOption` from
-
# ../../../lib/options.nix influences.
-
#
-
# Each element of `relatedPackages` can be either
-
# - a string: that will be interpreted as an attribute name from `pkgs`,
-
# - a list: that will be interpreted as an attribute path from `pkgs`,
-
# - an attrset: that can specify `name`, `path`, `package`, `comment`
-
# (either of `name`, `path` is required, the rest are optional).
-
genRelatedPackages = packages:
-
let
-
unpack = p: if lib.isString p then { name = p; }
-
else if lib.isList p then { path = p; }
-
else p;
-
describe = args:
-
let
-
title = args.title or null;
-
name = args.name or (lib.concatStringsSep "." args.path);
-
path = args.path or [ args.name ];
-
package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}'") pkgs);
-
in "<listitem>"
-
+ "<para><literal>${lib.optionalString (title != null) "${title} aka "}pkgs.${name} (${package.meta.name})</literal>"
-
+ lib.optionalString (!package.meta.available) " <emphasis>[UNAVAILABLE]</emphasis>"
-
+ ": ${package.meta.description or "???"}.</para>"
-
+ lib.optionalString (args ? comment) "\n<para>${args.comment}</para>"
-
# Lots of `longDescription's break DocBook, so we just wrap them into <programlisting>
-
+ lib.optionalString (package.meta ? longDescription) "\n<programlisting>${package.meta.longDescription}</programlisting>"
-
+ "</listitem>";
-
in "<itemizedlist>${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}</itemizedlist>";
-
-
optionsListDesc = lib.flip map optionsListVisible (opt: opt // {
-
# Clean up declaration sites to not refer to the NixOS source tree.
-
declarations = map stripAnyPrefixes opt.declarations;
-
}
-
// lib.optionalAttrs (opt ? example) { example = substFunction opt.example; }
-
// lib.optionalAttrs (opt ? default) { default = substFunction opt.default; }
-
// lib.optionalAttrs (opt ? type) { type = substFunction opt.type; }
-
// lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages; });
-
# We need to strip references to /nix/store/* from options,
# including any `extraSources` if some modules came from elsewhere,
# or else the build will fail.
···
prefixesToStrip = map (p: "${toString p}/") ([ ../../.. ] ++ extraSources);
stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) prefixesToStrip;
-
# Custom "less" that pushes up all the things ending in ".enable*"
-
# and ".package*"
-
optionLess = a: b:
-
let
-
ise = lib.hasPrefix "enable";
-
isp = lib.hasPrefix "package";
-
cmp = lib.splitByAndCompare ise lib.compare
-
(lib.splitByAndCompare isp lib.compare lib.compare);
-
in lib.compareLists cmp a.loc b.loc < 0;
-
-
# Customly sort option list for the man page.
-
optionsList = lib.sort optionLess optionsListDesc;
-
-
# Convert the list of options into an XML file.
-
optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList);
-
-
optionsDocBook = runCommand "options-db.xml" {} ''
-
optionsXML=${optionsXML}
-
if grep /nixpkgs/nixos/modules $optionsXML; then
-
echo "The manual appears to depend on the location of Nixpkgs, which is bad"
-
echo "since this prevents sharing via the NixOS channel. This is typically"
-
echo "caused by an option default that refers to a relative path (see above"
-
echo "for hints about the offending path)."
-
exit 1
-
fi
-
${buildPackages.libxslt.bin}/bin/xsltproc \
-
--stringparam revision '${revision}' \
-
-o intermediate.xml ${./options-to-docbook.xsl} $optionsXML
-
${buildPackages.libxslt.bin}/bin/xsltproc \
-
-o "$out" ${./postprocess-option-descriptions.xsl} intermediate.xml
-
'';
+
optionsDoc = buildPackages.nixosOptionsDoc {
+
inherit options revision;
+
transformOptions = opt: opt // {
+
# Clean up declaration sites to not refer to the NixOS source tree.
+
declarations = map stripAnyPrefixes opt.declarations;
+
};
+
};
sources = lib.sourceFilesBySuffices ./. [".xml"];
···
generatedSources = runCommand "generated-docbook" {} ''
mkdir $out
ln -s ${modulesDoc} $out/modules.xml
-
ln -s ${optionsDocBook} $out/options-db.xml
+
ln -s ${optionsDoc.optionsDocBook} $out/options-db.xml
printf "%s" "${version}" > $out/version
'';
···
in rec {
inherit generatedSources;
-
# The NixOS options in JSON format.
-
optionsJSON = runCommand "options-json"
-
{ meta.description = "List of NixOS options in JSON format";
-
}
-
''
-
# Export list of options in different format.
-
dst=$out/share/doc/nixos
-
mkdir -p $dst
-
-
cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON
-
(builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList))))
-
} $dst/options.json
-
-
mkdir -p $out/nix-support
-
echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products
-
''; # */
+
inherit (optionsDoc) optionsJSON optionsXML optionsDocBook;
# Generate the NixOS manual.
manualHTML = runCommand "nixos-manual-html"
nixos/doc/manual/options-to-docbook.xsl nixos/lib/make-options-doc/options-to-docbook.xsl
nixos/doc/manual/postprocess-option-descriptions.xsl nixos/lib/make-options-doc/postprocess-option-descriptions.xsl
+125
nixos/lib/make-options-doc/default.nix
···
+
/* Generate JSON, XML and DocBook documentation for given NixOS options.
+
+
Minimal example:
+
+
{ pkgs, }:
+
+
let
+
eval = import (pkgs.path + "/nixos/lib/eval-config.nix") {
+
baseModules = [
+
../module.nix
+
];
+
modules = [];
+
};
+
in pkgs.nixosOptionsDoc {
+
options = eval.options;
+
}
+
+
*/
+
{ pkgs
+
, lib
+
, options
+
, transformOptions ? lib.id # function for additional tranformations of the options
+
, revision ? "" # Specify revision for the options
+
}:
+
+
let
+
# Replace functions by the string <function>
+
substFunction = x:
+
if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x
+
else if builtins.isList x then map substFunction x
+
else if lib.isFunction x then "<function>"
+
else x;
+
+
optionsListDesc = lib.flip map optionsListVisible
+
(opt: transformOptions opt
+
// lib.optionalAttrs (opt ? example) { example = substFunction opt.example; }
+
// lib.optionalAttrs (opt ? default) { default = substFunction opt.default; }
+
// lib.optionalAttrs (opt ? type) { type = substFunction opt.type; }
+
// lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages; }
+
);
+
+
# Generate DocBook documentation for a list of packages. This is
+
# what `relatedPackages` option of `mkOption` from
+
# ../../../lib/options.nix influences.
+
#
+
# Each element of `relatedPackages` can be either
+
# - a string: that will be interpreted as an attribute name from `pkgs`,
+
# - a list: that will be interpreted as an attribute path from `pkgs`,
+
# - an attrset: that can specify `name`, `path`, `package`, `comment`
+
# (either of `name`, `path` is required, the rest are optional).
+
genRelatedPackages = packages:
+
let
+
unpack = p: if lib.isString p then { name = p; }
+
else if lib.isList p then { path = p; }
+
else p;
+
describe = args:
+
let
+
title = args.title or null;
+
name = args.name or (lib.concatStringsSep "." args.path);
+
path = args.path or [ args.name ];
+
package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}'") pkgs);
+
in "<listitem>"
+
+ "<para><literal>${lib.optionalString (title != null) "${title} aka "}pkgs.${name} (${package.meta.name})</literal>"
+
+ lib.optionalString (!package.meta.available) " <emphasis>[UNAVAILABLE]</emphasis>"
+
+ ": ${package.meta.description or "???"}.</para>"
+
+ lib.optionalString (args ? comment) "\n<para>${args.comment}</para>"
+
# Lots of `longDescription's break DocBook, so we just wrap them into <programlisting>
+
+ lib.optionalString (package.meta ? longDescription) "\n<programlisting>${package.meta.longDescription}</programlisting>"
+
+ "</listitem>";
+
in "<itemizedlist>${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}</itemizedlist>";
+
+
# Custom "less" that pushes up all the things ending in ".enable*"
+
# and ".package*"
+
optionLess = a: b:
+
let
+
ise = lib.hasPrefix "enable";
+
isp = lib.hasPrefix "package";
+
cmp = lib.splitByAndCompare ise lib.compare
+
(lib.splitByAndCompare isp lib.compare lib.compare);
+
in lib.compareLists cmp a.loc b.loc < 0;
+
+
# Remove invisible and internal options.
+
optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options);
+
+
# Customly sort option list for the man page.
+
optionsList = lib.sort optionLess optionsListDesc;
+
+
# Convert the list of options into an XML file.
+
optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList);
+
+
in rec {
+
# The NixOS options in JSON format.
+
optionsJSON = pkgs.runCommand "options.json"
+
{ meta.description = "List of NixOS options in JSON format";
+
}
+
''
+
# Export list of options in different format.
+
dst=$out/share/doc/nixos
+
mkdir -p $dst
+
+
cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON
+
(builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList))))
+
} $dst/options.json
+
+
mkdir -p $out/nix-support
+
echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products
+
''; # */
+
+
optionsDocBook = pkgs.runCommand "options-docbook.xml" {} ''
+
optionsXML=${optionsXML}
+
if grep /nixpkgs/nixos/modules $optionsXML; then
+
echo "The manual appears to depend on the location of Nixpkgs, which is bad"
+
echo "since this prevents sharing via the NixOS channel. This is typically"
+
echo "caused by an option default that refers to a relative path (see above"
+
echo "for hints about the offending path)."
+
exit 1
+
fi
+
+
${pkgs.libxslt.bin}/bin/xsltproc \
+
--stringparam revision '${revision}' \
+
-o intermediate.xml ${./options-to-docbook.xsl} $optionsXML
+
${pkgs.libxslt.bin}/bin/xsltproc \
+
-o "$out" ${./postprocess-option-descriptions.xsl} intermediate.xml
+
'';
+
}
+4
pkgs/top-level/all-packages.nix
···
nixosTesting.makeTest calledTest;
+
nixosOptionsDoc = attrs:
+
(import ../../nixos/lib/make-options-doc/default.nix)
+
({ inherit pkgs lib; } // attrs);
+
nixui = callPackage ../tools/package-management/nixui { node_webkit = nwjs_0_12; };
nixdoc = callPackage ../tools/nix/nixdoc {};