diff --git a/lib/default.nix b/lib/default.nix index 97d7c10192a..77cfa712557 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -56,7 +56,8 @@ let 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; @@ -71,8 +72,8 @@ let 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 diff --git a/lib/lists.nix b/lib/lists.nix index f2e6bacdc98..424d2c57f55 100644 --- a/lib/lists.nix +++ b/lib/lists.nix @@ -385,6 +385,30 @@ rec { 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: diff --git a/lib/options.nix b/lib/options.nix index 769d3cc5572..e10c86dd506 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -14,6 +14,7 @@ rec { , 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. @@ -76,7 +77,6 @@ rec { 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' []; @@ -93,9 +93,10 @@ rec { 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; diff --git a/lib/trivial.nix b/lib/trivial.nix index d8d51298143..a928e1dbca9 100644 --- a/lib/trivial.nix +++ b/lib/trivial.nix @@ -81,6 +81,42 @@ rec { */ 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); diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index 8079a2feb29..66fa4f0ba43 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -6,7 +6,7 @@ let 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 substFunction = x: @@ -15,13 +15,43 @@ let else if lib.isFunction x then "" 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 "" + + "pkgs.${name} (${package.meta.name})" + + lib.optionalString (!package.meta.evaluates) " [UNAVAILABLE]" + + ": ${package.meta.description or "???"}." + + lib.optionalString (args ? comment) "\n${args.comment}" + # Lots of `longDescription's break DocBook, so we just wrap them into + + lib.optionalString (package.meta ? longDescription) "\n${package.meta.longDescription}" + + ""; + in "${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}"; + + 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, @@ -32,8 +62,22 @@ let 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} @@ -191,7 +235,7 @@ in rec { 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 diff --git a/nixos/doc/manual/options-to-docbook.xsl b/nixos/doc/manual/options-to-docbook.xsl index 5387546b598..7b45b233ab2 100644 --- a/nixos/doc/manual/options-to-docbook.xsl +++ b/nixos/doc/manual/options-to-docbook.xsl @@ -70,6 +70,15 @@ + + + Related packages: + + + + + Declared by: diff --git a/nixos/modules/programs/adb.nix b/nixos/modules/programs/adb.nix index 18290555b79..f648d70bd9f 100644 --- a/nixos/modules/programs/adb.nix +++ b/nixos/modules/programs/adb.nix @@ -16,6 +16,7 @@ with lib; To grant access to a user, it must be part of adbusers group: users.extraUsers.alice.extraGroups = ["adbusers"]; ''; + relatedPackages = [ ["androidenv" "platformTools"] ]; }; }; }; diff --git a/nixos/modules/programs/tmux.nix b/nixos/modules/programs/tmux.nix index 1eb6fa6bf2f..4a60403a282 100644 --- a/nixos/modules/programs/tmux.nix +++ b/nixos/modules/programs/tmux.nix @@ -61,7 +61,12 @@ in { options = { programs.tmux = { - enable = mkEnableOption "tmux - a screen replacement."; + enable = mkOption { + type = types.bool; + default = false; + description = "Whenever to configure tmux system-wide."; + relatedPackages = [ "tmux" ]; + }; aggressiveResize = mkOption { default = false; diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 562be13a3f6..7351482f957 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -210,6 +210,7 @@ with lib; "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" ]) @@ -220,5 +221,8 @@ with lib; (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" ]) ]; } diff --git a/nixos/modules/virtualisation/xen-dom0.nix b/nixos/modules/virtualisation/xen-dom0.nix index c7656bc309c..afc5a42f8b4 100644 --- a/nixos/modules/virtualisation/xen-dom0.nix +++ b/nixos/modules/virtualisation/xen-dom0.nix @@ -35,24 +35,19 @@ in 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 = @@ -158,8 +153,7 @@ in } ]; 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 ]; @@ -339,7 +333,8 @@ in 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 ''; }; @@ -448,7 +443,7 @@ in 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"; diff --git a/pkgs/applications/virtualization/qemu/default.nix b/pkgs/applications/virtualization/qemu/default.nix index 91b02f7ad1f..68ab979ecfb 100644 --- a/pkgs/applications/virtualization/qemu/default.nix +++ b/pkgs/applications/virtualization/qemu/default.nix @@ -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 ""; + 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"; diff --git a/pkgs/applications/virtualization/xen/4.5.nix b/pkgs/applications/virtualization/xen/4.5.nix index ec3fe9ccf22..22799a7af8e 100644 --- a/pkgs/applications/virtualization/xen/4.5.nix +++ b/pkgs/applications/virtualization/xen/4.5.nix @@ -248,4 +248,10 @@ callPackage (import ./generic.nix (rec { -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) diff --git a/pkgs/applications/virtualization/xen/4.8.nix b/pkgs/applications/virtualization/xen/4.8.nix index 6eedca18960..44a52a1026a 100644 --- a/pkgs/applications/virtualization/xen/4.8.nix +++ b/pkgs/applications/virtualization/xen/4.8.nix @@ -176,4 +176,10 @@ callPackage (import ./generic.nix (rec { -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