Merge pull request #33898 from oxij/nixos/related-packages-v5

nixos: doc: implement related packages in the manual (again)

Changed files
+165 -29
lib
nixos
doc
modules
programs
virtualisation
pkgs
applications
virtualization
+4 -3
lib/default.nix
···
replaceStrings seq stringLength sub substring tail;
inherit (trivial) id const concat or and boolToString mergeAttrs
flip mapNullable inNixShell min max importJSON warn info
-
nixpkgsVersion mod functionArgs setFunctionArgs isFunction;
+
nixpkgsVersion mod compare splitByAndCompare
+
functionArgs setFunctionArgs isFunction;
inherit (fixedPoints) fix fix' extends composeExtensions
makeExtensible makeExtensibleWithCustomName;
···
inherit (lists) singleton foldr fold foldl foldl' imap0 imap1
concatMap flatten remove findSingle findFirst any all count
optional optionals toList range partition zipListsWith zipLists
-
reverseList listDfs toposort sort take drop sublist last init
-
crossLists unique intersectLists subtractLists
+
reverseList listDfs toposort sort compareLists take drop sublist
+
last init crossLists unique intersectLists subtractLists
mutuallyExclusive;
inherit (strings) concatStrings concatMapStrings concatImapStrings
intersperse concatStringsSep concatMapStringsSep
+24
lib/lists.nix
···
if len < 2 then list
else (sort strictLess pivot.left) ++ [ first ] ++ (sort strictLess pivot.right));
+
/* Compare two lists element-by-element.
+
+
Example:
+
compareLists compare [] []
+
=> 0
+
compareLists compare [] [ "a" ]
+
=> -1
+
compareLists compare [ "a" ] []
+
=> 1
+
compareLists compare [ "a" "b" ] [ "a" "c" ]
+
=> 1
+
*/
+
compareLists = cmp: a: b:
+
if a == []
+
then if b == []
+
then 0
+
else -1
+
else if b == []
+
then 1
+
else let rel = cmp (head a) (head b); in
+
if rel == 0
+
then compareLists cmp (tail a) (tail b)
+
else rel;
+
/* Return the first (at most) N elements of a list.
Example:
+5 -4
lib/options.nix
···
, defaultText ? null # Textual representation of the default, for in the manual.
, example ? null # Example value used in the manual.
, description ? null # String describing the option.
+
, relatedPackages ? null # Related packages used in the manual (see `genRelatedPackages` in ../nixos/doc/manual/default.nix).
, type ? null # Option type, providing type-checking and value merging.
, apply ? null # Function that converts the option value to something else.
, internal ? null # Whether the option is for NixOS developers only.
···
getValues = map (x: x.value);
getFiles = map (x: x.file);
-
# Generate documentation template from the list of option declaration like
# the set generated with filterOptionSets.
optionAttrSetToDocList = optionAttrSetToDocList' [];
···
readOnly = opt.readOnly or false;
type = opt.type.description or null;
}
-
// (if opt ? example then { example = scrubOptionValue opt.example; } else {})
-
// (if opt ? default then { default = scrubOptionValue opt.default; } else {})
-
// (if opt ? defaultText then { default = opt.defaultText; } else {});
+
// optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; }
+
// optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; }
+
// optionalAttrs (opt ? defaultText) { default = opt.defaultText; }
+
// optionalAttrs (opt ? relatedPackages && opt.relatedPackages != null) { inherit (opt) relatedPackages; };
subOptions =
let ss = opt.type.getSubOptions opt.loc;
+36
lib/trivial.nix
···
*/
mod = base: int: base - (int * (builtins.div base int));
+
/* C-style comparisons
+
+
a < b, compare a b => -1
+
a == b, compare a b => 0
+
a > b, compare a b => 1
+
*/
+
compare = a: b:
+
if a < b
+
then -1
+
else if a > b
+
then 1
+
else 0;
+
+
/* Split type into two subtypes by predicate `p`, take all elements
+
of the first subtype to be less than all the elements of the
+
second subtype, compare elements of a single subtype with `yes`
+
and `no` respectively.
+
+
Example:
+
+
let cmp = splitByAndCompare (hasPrefix "foo") compare compare; in
+
+
cmp "a" "z" => -1
+
cmp "fooa" "fooz" => -1
+
+
cmp "f" "a" => 1
+
cmp "fooa" "a" => -1
+
# while
+
compare "fooa" "a" => 1
+
+
*/
+
splitByAndCompare = p: yes: no: a: b:
+
if p a
+
then if p b then yes a b else -1
+
else if p b then 1 else no a b;
+
/* Reads a JSON file. */
importJSON = path:
builtins.fromJSON (builtins.readFile path);
+50 -6
nixos/doc/manual/default.nix
···
lib = pkgs.lib;
# Remove invisible and internal options.
-
optionsList = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options);
+
optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options);
# Replace functions by the string <function>
substFunction = x:
···
else if lib.isFunction x then "<function>"
else x;
-
# Clean up declaration sites to not refer to the NixOS source tree.
-
optionsList' = lib.flip map optionsList (opt: opt // {
+
# 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
+
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>pkgs.${name} (${package.meta.name})</literal>"
+
+ lib.optionalString (!package.meta.evaluates) " <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 ? type) { type = substFunction opt.type; }
+
// lib.optionalAttrs (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,
···
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"
+
optionListLess = a: b:
+
let
+
splt = lib.splitString ".";
+
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 (splt a) (splt b) < 0;
+
+
# Customly sort option list for the man page.
+
optionsList = lib.sort (a: b: optionListLess a.name b.name) optionsListDesc;
+
# Convert the list of options into an XML file.
-
optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList');
+
optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList);
optionsDocBook = runCommand "options-db.xml" {} ''
optionsXML=${optionsXML}
···
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'))))
+
(builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList))))
} $dst/options.json
mkdir -p $out/nix-support
+9
nixos/doc/manual/options-to-docbook.xsl
···
</para>
</xsl:if>
+
<xsl:if test="attr[@name = 'relatedPackages']">
+
<para>
+
<emphasis>Related packages:</emphasis>
+
<xsl:text> </xsl:text>
+
<xsl:value-of disable-output-escaping="yes"
+
select="attr[@name = 'relatedPackages']/string/@value" />
+
</para>
+
</xsl:if>
+
<xsl:if test="count(attr[@name = 'declarations']/list/*) != 0">
<para>
<emphasis>Declared by:</emphasis>
+1
nixos/modules/programs/adb.nix
···
To grant access to a user, it must be part of adbusers group:
<code>users.extraUsers.alice.extraGroups = ["adbusers"];</code>
'';
+
relatedPackages = [ ["androidenv" "platformTools"] ];
};
};
};
+6 -1
nixos/modules/programs/tmux.nix
···
options = {
programs.tmux = {
-
enable = mkEnableOption "<command>tmux</command> - a <command>screen</command> replacement.";
+
enable = mkOption {
+
type = types.bool;
+
default = false;
+
description = "Whenever to configure <command>tmux</command> system-wide.";
+
relatedPackages = [ "tmux" ];
+
};
aggressiveResize = mkOption {
default = false;
+4
nixos/modules/rename.nix
···
"Set the option `services.xserver.displayManager.sddm.package' instead.")
(mkRemovedOptionModule [ "fonts" "fontconfig" "forceAutohint" ] "")
(mkRemovedOptionModule [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ] "")
+
(mkRemovedOptionModule [ "virtualisation" "xen" "qemu" ] "You don't need this option anymore, it will work without it.")
# ZSH
(mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ])
···
(mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "theme" ] [ "programs" "zsh" "ohMyZsh" "theme" ])
(mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "custom" ] [ "programs" "zsh" "ohMyZsh" "custom" ])
(mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "plugins" ] [ "programs" "zsh" "ohMyZsh" "plugins" ])
+
+
# Xen
+
(mkRenamedOptionModule [ "virtualisation" "xen" "qemu-package" ] [ "virtualisation" "xen" "package-qemu" ])
];
}
+10 -15
nixos/modules/virtualisation/xen-dom0.nix
···
description = ''
The package used for Xen binary.
'';
+
relatedPackages = [ "xen" "xen-light" ];
};
-
virtualisation.xen.qemu = mkOption {
-
type = types.path;
-
defaultText = "\${pkgs.xen}/lib/xen/bin/qemu-system-i386";
-
example = literalExample "''${pkgs.qemu_xen-light}/bin/qemu-system-i386";
-
description = ''
-
The qemu binary to use for Dom-0 backend.
-
'';
-
};
-
-
virtualisation.xen.qemu-package = mkOption {
+
virtualisation.xen.package-qemu = mkOption {
type = types.package;
defaultText = "pkgs.xen";
example = literalExample "pkgs.qemu_xen-light";
description = ''
-
The package with qemu binaries for xendomains.
+
The package with qemu binaries for dom0 qemu and xendomains.
'';
+
relatedPackages = [ "xen"
+
{ name = "qemu_xen-light"; comment = "For use with pkgs.xen-light."; }
+
];
};
virtualisation.xen.bootParams =
···
} ];
virtualisation.xen.package = mkDefault pkgs.xen;
-
virtualisation.xen.qemu = mkDefault "${pkgs.xen}/lib/xen/bin/qemu-system-i386";
-
virtualisation.xen.qemu-package = mkDefault pkgs.xen;
+
virtualisation.xen.package-qemu = mkDefault pkgs.xen;
virtualisation.xen.stored = mkDefault "${cfg.package}/bin/oxenstored";
environment.systemPackages = [ cfg.package ];
···
after = [ "xen-console.service" ];
requires = [ "xen-store.service" ];
serviceConfig.ExecStart = ''
-
${cfg.qemu} -xen-attach -xen-domid 0 -name dom0 -M xenpv \
+
${cfg.package-qemu}/${cfg.package-qemu.qemu-system-i386} \
+
-xen-attach -xen-domid 0 -name dom0 -M xenpv \
-nographic -monitor /dev/null -serial /dev/null -parallel /dev/null
'';
};
···
before = [ "dhcpd.service" ];
restartIfChanged = false;
serviceConfig.RemainAfterExit = "yes";
-
path = [ cfg.package cfg.qemu-package ];
+
path = [ cfg.package cfg.package-qemu ];
environment.XENDOM_CONFIG = "${cfg.package}/etc/sysconfig/xendomains";
preStart = "mkdir -p /var/lock/subsys -m 755";
serviceConfig.ExecStart = "${cfg.package}/etc/init.d/xendomains start";
+4
pkgs/applications/virtualization/qemu/default.nix
···
else if stdenv.isAarch64 then ''makeWrapper $out/bin/qemu-system-aarch64 $out/bin/qemu-kvm --add-flags "\$([ -e /dev/kvm ] && echo -enable-kvm)"''
else "";
+
passthru = {
+
qemu-system-i386 = "bin/qemu-system-i386";
+
};
+
meta = with stdenv.lib; {
homepage = http://www.qemu.org/;
description = "A generic and open source machine emulator and virtualizer";
+6
pkgs/applications/virtualization/xen/4.5.nix
···
-i tools/libxl/libxl_device.c
'';
+
passthru = {
+
qemu-system-i386 = if withInternalQemu
+
then "lib/xen/bin/qemu-system-i386"
+
else throw "this xen has no qemu builtin";
+
};
+
})) ({ ocamlPackages = ocamlPackages_4_02; } // args)
+6
pkgs/applications/virtualization/xen/4.8.nix
···
-i tools/libxl/libxl_device.c
'';
+
passthru = {
+
qemu-system-i386 = if withInternalQemu
+
then "lib/xen/bin/qemu-system-i386"
+
else throw "this xen has no qemu builtin";
+
};
+
})) args