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 - ??
This commit is contained in:
parent
9175a201bb
commit
5cfd034af0
@ -5,55 +5,6 @@ with pkgs;
|
|||||||
let
|
let
|
||||||
lib = pkgs.lib;
|
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,
|
# We need to strip references to /nix/store/* from options,
|
||||||
# including any `extraSources` if some modules came from elsewhere,
|
# including any `extraSources` if some modules came from elsewhere,
|
||||||
# or else the build will fail.
|
# or else the build will fail.
|
||||||
@ -63,37 +14,13 @@ let
|
|||||||
prefixesToStrip = map (p: "${toString p}/") ([ ../../.. ] ++ extraSources);
|
prefixesToStrip = map (p: "${toString p}/") ([ ../../.. ] ++ extraSources);
|
||||||
stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) prefixesToStrip;
|
stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) prefixesToStrip;
|
||||||
|
|
||||||
# Custom "less" that pushes up all the things ending in ".enable*"
|
optionsDoc = buildPackages.nixosOptionsDoc {
|
||||||
# and ".package*"
|
inherit options revision;
|
||||||
optionLess = a: b:
|
transformOptions = opt: opt // {
|
||||||
let
|
# Clean up declaration sites to not refer to the NixOS source tree.
|
||||||
ise = lib.hasPrefix "enable";
|
declarations = map stripAnyPrefixes opt.declarations;
|
||||||
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
|
|
||||||
'';
|
|
||||||
|
|
||||||
sources = lib.sourceFilesBySuffices ./. [".xml"];
|
sources = lib.sourceFilesBySuffices ./. [".xml"];
|
||||||
|
|
||||||
@ -108,7 +35,7 @@ let
|
|||||||
generatedSources = runCommand "generated-docbook" {} ''
|
generatedSources = runCommand "generated-docbook" {} ''
|
||||||
mkdir $out
|
mkdir $out
|
||||||
ln -s ${modulesDoc} $out/modules.xml
|
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
|
printf "%s" "${version}" > $out/version
|
||||||
'';
|
'';
|
||||||
|
|
||||||
@ -234,22 +161,7 @@ let
|
|||||||
in rec {
|
in rec {
|
||||||
inherit generatedSources;
|
inherit generatedSources;
|
||||||
|
|
||||||
# The NixOS options in JSON format.
|
inherit (optionsDoc) optionsJSON optionsXML optionsDocBook;
|
||||||
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
|
|
||||||
''; # */
|
|
||||||
|
|
||||||
# Generate the NixOS manual.
|
# Generate the NixOS manual.
|
||||||
manualHTML = runCommand "nixos-manual-html"
|
manualHTML = runCommand "nixos-manual-html"
|
||||||
|
125
nixos/lib/make-options-doc/default.nix
Normal file
125
nixos/lib/make-options-doc/default.nix
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/* 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
|
||||||
|
'';
|
||||||
|
}
|
@ -23876,6 +23876,10 @@ in
|
|||||||
in
|
in
|
||||||
nixosTesting.makeTest calledTest;
|
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; };
|
nixui = callPackage ../tools/package-management/nixui { node_webkit = nwjs_0_12; };
|
||||||
|
|
||||||
nixdoc = callPackage ../tools/nix/nixdoc {};
|
nixdoc = callPackage ../tools/nix/nixdoc {};
|
||||||
|
Loading…
Reference in New Issue
Block a user