summary refs log tree commit diff
diff options
context:
space:
mode:
authorAnselm Schüler <mail@anselmschueler.com>2022-02-20 16:17:28 +0100
committerpennae <82953136+pennae@users.noreply.github.com>2023-02-26 03:00:22 +0100
commit9769e9023340c673d9c15f91efa89f0787b9a564 (patch)
tree4b6da3731ccaf1ef7d1d9aa9b65f9a36a9aa6dfc
parentd6ae1560b053814f019a13932c64760ce9576b1c (diff)
downloadnixpkgs-9769e9023340c673d9c15f91efa89f0787b9a564.tar
nixpkgs-9769e9023340c673d9c15f91efa89f0787b9a564.tar.gz
nixpkgs-9769e9023340c673d9c15f91efa89f0787b9a564.tar.bz2
nixpkgs-9769e9023340c673d9c15f91efa89f0787b9a564.tar.lz
nixpkgs-9769e9023340c673d9c15f91efa89f0787b9a564.tar.xz
nixpkgs-9769e9023340c673d9c15f91efa89f0787b9a564.tar.zst
nixpkgs-9769e9023340c673d9c15f91efa89f0787b9a564.zip
lib/options: Add more options to mkPackageOption
-rw-r--r--lib/options.nix63
-rw-r--r--nixos/doc/manual/development/option-declarations.section.md34
2 files changed, 79 insertions, 18 deletions
diff --git a/lib/options.nix b/lib/options.nix
index b88af070513..20e8fb8d5ed 100644
--- a/lib/options.nix
+++ b/lib/options.nix
@@ -36,6 +36,9 @@ let
   inherit (lib.types)
     mkOptionType
     ;
+  inherit (lib.lists)
+    last
+    ;
   prioritySuggestion = ''
    Use `lib.mkForce value` or `lib.mkDefault value` to change the priority on any of these definitions.
   '';
@@ -107,17 +110,28 @@ rec {
   /* Creates an Option attribute set for an option that specifies the
      package a module should use for some purpose.
 
-     The package is specified as a list of strings representing its attribute path in nixpkgs.
+     Type: mkPackageOption :: pkgs -> (string|[string]) ->
+      { default? :: [string], example? :: null|string|[string], extraDescription? :: string } ->
+      option
 
-     Because of this, you need to pass nixpkgs itself as the first argument.
+     The package is specified in the third argument under `default` as a list of strings
+     representing its attribute path in nixpkgs (or another package set).
+     Because of this, you need to pass nixpkgs itself (or a subset) as the first argument.
 
-     The second argument is the name of the option, used in the description "The <name> package to use.".
+     The second argument may be either a string or a list of strings.
+     It provides the display name of the package in the description of the generated option
+     (using only the last element if the passed value is a list)
+     and serves as the fallback value for the `default` argument.
 
-     You can also pass an example value, either a literal string or a package's attribute path.
+     To include extra information in the description, pass `extraDescription` to
+     append arbitrary text to the generated description.
+     You can also pass an `example` value, either a literal string or an attribute path.
 
-     You can omit the default path if the name of the option is also attribute path in nixpkgs.
+     The default argument can be omitted if the provided name is
+     an attribute of pkgs (if name is a string) or a
+     valid attribute path in pkgs (if name is a list).
 
-     Type: mkPackageOption :: pkgs -> string -> { default :: [string]; example :: null | string | [string]; } -> option
+     If you wish to explicitly provide no default, pass `null` as `default`.
 
      Example:
        mkPackageOption pkgs "hello" { }
@@ -129,27 +143,46 @@ rec {
          example = "pkgs.haskell.packages.ghc92.ghc.withPackages (hkgs: [ hkgs.primes ])";
        }
        => { _type = "option"; default = «derivation /nix/store/jxx55cxsjrf8kyh3fp2ya17q99w7541r-ghc-8.10.7.drv»; defaultText = { ... }; description = "The GHC package to use."; example = { ... }; type = { ... }; }
+
+     Example:
+       mkPackageOption pkgs [ "python39Packages" "pytorch" ] {
+         extraDescription = "This is an example and doesn't actually do anything.";
+       }
+       => { _type = "option"; default = «derivation /nix/store/gvqgsnc4fif9whvwd9ppa568yxbkmvk8-python3.9-pytorch-1.10.2.drv»; defaultText = { ... }; description = "The pytorch package to use. This is an example and doesn't actually do anything."; type = { ... }; }
+
   */
   mkPackageOption =
-    # Package set (a specific version of nixpkgs)
+    # Package set (a specific version of nixpkgs or a subset)
     pkgs:
       # Name for the package, shown in option description
       name:
-      { default ? [ name ], example ? null }:
-      let default' = if !isList default then [ default ] else default;
+      {
+        # The attribute path where the default package is located
+        default ? name,
+        # A string or an attribute path to use as an example
+        example ? null,
+        # Additional text to include in the option description
+        extraDescription ? "",
+      }:
+      let
+        name' = if isList name then last name else name;
+        default' = if isList default then default else [ default ];
+        defaultPath = concatStringsSep "." default';
+        defaultValue = attrByPath default'
+          (throw "${defaultPath} cannot be found in pkgs") pkgs;
       in mkOption {
+        defaultText = literalExpression ("pkgs." + defaultPath);
         type = lib.types.package;
-        description = "The ${name} package to use.";
-        default = attrByPath default'
-          (throw "${concatStringsSep "." default'} cannot be found in pkgs") pkgs;
-        defaultText = literalExpression ("pkgs." + concatStringsSep "." default');
+        description = "The ${name'} package to use."
+          + (if extraDescription == "" then "" else " ") + extraDescription;
+        ${if default != null then "default" else null} = defaultValue;
         ${if example != null then "example" else null} = literalExpression
           (if isList example then "pkgs." + concatStringsSep "." example else example);
       };
 
   /* Like mkPackageOption, but emit an mdDoc description instead of DocBook. */
-  mkPackageOptionMD = args: name: extra:
-    let option = mkPackageOption args name extra;
+  mkPackageOptionMD = pkgs: name: extra:
+    let option = mkPackageOption pkgs name extra;
     in option // { description = lib.mdDoc option.description; };
 
   /* This option accepts anything, but it does not produce any result.
diff --git a/nixos/doc/manual/development/option-declarations.section.md b/nixos/doc/manual/development/option-declarations.section.md
index 59470bf1bc1..f6fed3e1683 100644
--- a/nixos/doc/manual/development/option-declarations.section.md
+++ b/nixos/doc/manual/development/option-declarations.section.md
@@ -101,11 +101,24 @@ Creates an Option attribute set for an option that specifies the package a modul
 
 **Note**: You shouldn’t necessarily make package options for all of your modules. You can always overwrite a specific package throughout nixpkgs by using [nixpkgs overlays](https://nixos.org/manual/nixpkgs/stable/#chap-overlays).
 
-The default package is specified as a list of strings representing its attribute path in nixpkgs. Because of this, you need to pass nixpkgs itself as the first argument.
+The package is specified in the third argument under `default` as a list of strings
+representing its attribute path in nixpkgs (or another package set).
+Because of this, you need to pass nixpkgs itself (or a subset) as the first argument.
 
-The second argument is the name of the option, used in the description "The \<name\> package to use.". You can also pass an example value, either a literal string or a package's attribute path.
+The second argument may be either a string or a list of strings.
+It provides the display name of the package in the description of the generated option
+(using only the last element if the passed value is a list)
+and serves as the fallback value for the `default` argument.
 
-You can omit the default path if the name of the option is also attribute path in nixpkgs.
+To include extra information in the description, pass `extraDescription` to
+append arbitrary text to the generated description.
+You can also pass an `example` value, either a literal string or an attribute path.
+
+The default argument can be omitted if the provided name is
+an attribute of pkgs (if name is a string) or a
+valid attribute path in pkgs (if name is a list).
+
+If you wish to explicitly provide no default, pass `null` as `default`.
 
 During the transition to CommonMark documentation `mkPackageOption` creates an option with a DocBook description attribute, once the transition is completed it will create a CommonMark description instead. `mkPackageOptionMD` always creates an option with a CommonMark description attribute and will be removed some time after the transition is completed.
 
@@ -142,6 +155,21 @@ lib.mkOption {
 ```
 :::
 
+::: {#ex-options-declarations-util-mkPackageOption-extraDescription .example}
+```nix
+mkPackageOption pkgs [ "python39Packages" "pytorch" ] {
+  extraDescription = "This is an example and doesn't actually do anything.";
+}
+# is like
+lib.mkOption {
+  type = lib.types.package;
+  default = pkgs.python39Packages.pytorch;
+  defaultText = lib.literalExpression "pkgs.python39Packages.pytorch";
+  description = "The pytorch package to use. This is an example and doesn't actually do anything.";
+}
+```
+:::
+
 ## Extensible Option Types {#sec-option-declarations-eot}
 
 Extensible option types is a feature that allow to extend certain types