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

nixos: doc: implement related packages in the manual (again)
This commit is contained in:
Graham Christensen 2018-02-09 20:36:27 -05:00 committed by GitHub
commit 5aabf0fc34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 165 additions and 29 deletions

View File

@ -56,7 +56,8 @@ let
replaceStrings seq stringLength sub substring tail; replaceStrings seq stringLength sub substring tail;
inherit (trivial) id const concat or and boolToString mergeAttrs inherit (trivial) id const concat or and boolToString mergeAttrs
flip mapNullable inNixShell min max importJSON warn info 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 inherit (fixedPoints) fix fix' extends composeExtensions
makeExtensible makeExtensibleWithCustomName; makeExtensible makeExtensibleWithCustomName;
@ -71,8 +72,8 @@ let
inherit (lists) singleton foldr fold foldl foldl' imap0 imap1 inherit (lists) singleton foldr fold foldl foldl' imap0 imap1
concatMap flatten remove findSingle findFirst any all count concatMap flatten remove findSingle findFirst any all count
optional optionals toList range partition zipListsWith zipLists optional optionals toList range partition zipListsWith zipLists
reverseList listDfs toposort sort take drop sublist last init reverseList listDfs toposort sort compareLists take drop sublist
crossLists unique intersectLists subtractLists last init crossLists unique intersectLists subtractLists
mutuallyExclusive; mutuallyExclusive;
inherit (strings) concatStrings concatMapStrings concatImapStrings inherit (strings) concatStrings concatMapStrings concatImapStrings
intersperse concatStringsSep concatMapStringsSep intersperse concatStringsSep concatMapStringsSep

View File

@ -385,6 +385,30 @@ rec {
if len < 2 then list if len < 2 then list
else (sort strictLess pivot.left) ++ [ first ] ++ (sort strictLess pivot.right)); 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. /* Return the first (at most) N elements of a list.
Example: Example:

View File

@ -14,6 +14,7 @@ rec {
, defaultText ? null # Textual representation of the default, for in the manual. , defaultText ? null # Textual representation of the default, for in the manual.
, example ? null # Example value used in the manual. , example ? null # Example value used in the manual.
, description ? null # String describing the option. , 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. , type ? null # Option type, providing type-checking and value merging.
, apply ? null # Function that converts the option value to something else. , apply ? null # Function that converts the option value to something else.
, internal ? null # Whether the option is for NixOS developers only. , internal ? null # Whether the option is for NixOS developers only.
@ -76,7 +77,6 @@ rec {
getValues = map (x: x.value); getValues = map (x: x.value);
getFiles = map (x: x.file); getFiles = map (x: x.file);
# Generate documentation template from the list of option declaration like # Generate documentation template from the list of option declaration like
# the set generated with filterOptionSets. # the set generated with filterOptionSets.
optionAttrSetToDocList = optionAttrSetToDocList' []; optionAttrSetToDocList = optionAttrSetToDocList' [];
@ -93,9 +93,10 @@ rec {
readOnly = opt.readOnly or false; readOnly = opt.readOnly or false;
type = opt.type.description or null; type = opt.type.description or null;
} }
// (if opt ? example then { example = scrubOptionValue opt.example; } else {}) // optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; }
// (if opt ? default then { default = scrubOptionValue opt.default; } else {}) // optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; }
// (if opt ? defaultText then { default = opt.defaultText; } else {}); // optionalAttrs (opt ? defaultText) { default = opt.defaultText; }
// optionalAttrs (opt ? relatedPackages && opt.relatedPackages != null) { inherit (opt) relatedPackages; };
subOptions = subOptions =
let ss = opt.type.getSubOptions opt.loc; let ss = opt.type.getSubOptions opt.loc;

View File

@ -81,6 +81,42 @@ rec {
*/ */
mod = base: int: base - (int * (builtins.div base int)); 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. */ /* Reads a JSON file. */
importJSON = path: importJSON = path:
builtins.fromJSON (builtins.readFile path); builtins.fromJSON (builtins.readFile path);

View File

@ -6,7 +6,7 @@ let
lib = pkgs.lib; lib = pkgs.lib;
# Remove invisible and internal options. # 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> # Replace functions by the string <function>
substFunction = x: substFunction = x:
@ -15,13 +15,43 @@ let
else if lib.isFunction x then "<function>" else if lib.isFunction x then "<function>"
else x; else x;
# Clean up declaration sites to not refer to the NixOS source tree. # Generate DocBook documentation for a list of packages. This is
optionsList' = lib.flip map optionsList (opt: opt // { # 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; declarations = map stripAnyPrefixes opt.declarations;
} }
// lib.optionalAttrs (opt ? example) { example = substFunction opt.example; } // lib.optionalAttrs (opt ? example) { example = substFunction opt.example; }
// lib.optionalAttrs (opt ? default) { default = substFunction opt.default; } // 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, # 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,
@ -32,8 +62,22 @@ 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*"
# 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. # 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" {} '' optionsDocBook = runCommand "options-db.xml" {} ''
optionsXML=${optionsXML} optionsXML=${optionsXML}
@ -191,7 +235,7 @@ in rec {
mkdir -p $dst mkdir -p $dst
cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON 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 } $dst/options.json
mkdir -p $out/nix-support mkdir -p $out/nix-support

View File

@ -70,6 +70,15 @@
</para> </para>
</xsl:if> </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"> <xsl:if test="count(attr[@name = 'declarations']/list/*) != 0">
<para> <para>
<emphasis>Declared by:</emphasis> <emphasis>Declared by:</emphasis>

View File

@ -16,6 +16,7 @@ with lib;
To grant access to a user, it must be part of adbusers group: To grant access to a user, it must be part of adbusers group:
<code>users.extraUsers.alice.extraGroups = ["adbusers"];</code> <code>users.extraUsers.alice.extraGroups = ["adbusers"];</code>
''; '';
relatedPackages = [ ["androidenv" "platformTools"] ];
}; };
}; };
}; };

View File

@ -61,7 +61,12 @@ in {
options = { options = {
programs.tmux = { 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 { aggressiveResize = mkOption {
default = false; default = false;

View File

@ -210,6 +210,7 @@ with lib;
"Set the option `services.xserver.displayManager.sddm.package' instead.") "Set the option `services.xserver.displayManager.sddm.package' instead.")
(mkRemovedOptionModule [ "fonts" "fontconfig" "forceAutohint" ] "") (mkRemovedOptionModule [ "fonts" "fontconfig" "forceAutohint" ] "")
(mkRemovedOptionModule [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ] "") (mkRemovedOptionModule [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ] "")
(mkRemovedOptionModule [ "virtualisation" "xen" "qemu" ] "You don't need this option anymore, it will work without it.")
# ZSH # ZSH
(mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ]) (mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ])
@ -220,5 +221,8 @@ with lib;
(mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "theme" ] [ "programs" "zsh" "ohMyZsh" "theme" ]) (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" "custom" ] [ "programs" "zsh" "ohMyZsh" "custom" ])
(mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "plugins" ] [ "programs" "zsh" "ohMyZsh" "plugins" ]) (mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "plugins" ] [ "programs" "zsh" "ohMyZsh" "plugins" ])
# Xen
(mkRenamedOptionModule [ "virtualisation" "xen" "qemu-package" ] [ "virtualisation" "xen" "package-qemu" ])
]; ];
} }

View File

@ -35,24 +35,19 @@ in
description = '' description = ''
The package used for Xen binary. The package used for Xen binary.
''; '';
relatedPackages = [ "xen" "xen-light" ];
}; };
virtualisation.xen.qemu = mkOption { virtualisation.xen.package-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 {
type = types.package; type = types.package;
defaultText = "pkgs.xen"; defaultText = "pkgs.xen";
example = literalExample "pkgs.qemu_xen-light"; example = literalExample "pkgs.qemu_xen-light";
description = '' 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.bootParams =
@ -158,8 +153,7 @@ in
} ]; } ];
virtualisation.xen.package = mkDefault pkgs.xen; virtualisation.xen.package = mkDefault pkgs.xen;
virtualisation.xen.qemu = mkDefault "${pkgs.xen}/lib/xen/bin/qemu-system-i386"; virtualisation.xen.package-qemu = mkDefault pkgs.xen;
virtualisation.xen.qemu-package = mkDefault pkgs.xen;
virtualisation.xen.stored = mkDefault "${cfg.package}/bin/oxenstored"; virtualisation.xen.stored = mkDefault "${cfg.package}/bin/oxenstored";
environment.systemPackages = [ cfg.package ]; environment.systemPackages = [ cfg.package ];
@ -339,7 +333,8 @@ in
after = [ "xen-console.service" ]; after = [ "xen-console.service" ];
requires = [ "xen-store.service" ]; requires = [ "xen-store.service" ];
serviceConfig.ExecStart = '' 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 -nographic -monitor /dev/null -serial /dev/null -parallel /dev/null
''; '';
}; };
@ -448,7 +443,7 @@ in
before = [ "dhcpd.service" ]; before = [ "dhcpd.service" ];
restartIfChanged = false; restartIfChanged = false;
serviceConfig.RemainAfterExit = "yes"; serviceConfig.RemainAfterExit = "yes";
path = [ cfg.package cfg.qemu-package ]; path = [ cfg.package cfg.package-qemu ];
environment.XENDOM_CONFIG = "${cfg.package}/etc/sysconfig/xendomains"; environment.XENDOM_CONFIG = "${cfg.package}/etc/sysconfig/xendomains";
preStart = "mkdir -p /var/lock/subsys -m 755"; preStart = "mkdir -p /var/lock/subsys -m 755";
serviceConfig.ExecStart = "${cfg.package}/etc/init.d/xendomains start"; serviceConfig.ExecStart = "${cfg.package}/etc/init.d/xendomains start";

View File

@ -101,6 +101,10 @@ stdenv.mkDerivation rec {
else if stdenv.isAarch64 then ''makeWrapper $out/bin/qemu-system-aarch64 $out/bin/qemu-kvm --add-flags "\$([ -e /dev/kvm ] && echo -enable-kvm)"'' else if stdenv.isAarch64 then ''makeWrapper $out/bin/qemu-system-aarch64 $out/bin/qemu-kvm --add-flags "\$([ -e /dev/kvm ] && echo -enable-kvm)"''
else ""; else "";
passthru = {
qemu-system-i386 = "bin/qemu-system-i386";
};
meta = with stdenv.lib; { meta = with stdenv.lib; {
homepage = http://www.qemu.org/; homepage = http://www.qemu.org/;
description = "A generic and open source machine emulator and virtualizer"; description = "A generic and open source machine emulator and virtualizer";

View File

@ -248,4 +248,10 @@ callPackage (import ./generic.nix (rec {
-i tools/libxl/libxl_device.c -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) })) ({ ocamlPackages = ocamlPackages_4_02; } // args)

View File

@ -176,4 +176,10 @@ callPackage (import ./generic.nix (rec {
-i tools/libxl/libxl_device.c -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 })) args