| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | # Nixpkgs/NixOS option handling. | 
					
						
							| 
									
										
										
										
											2017-07-28 20:05:35 -04:00
										 |  |  | { lib }: | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 20:05:35 -04:00
										 |  |  | with lib.trivial; | 
					
						
							|  |  |  | with lib.lists; | 
					
						
							|  |  |  | with lib.attrsets; | 
					
						
							|  |  |  | with lib.strings; | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | rec { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |   /* Returns true when the given argument is an option
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: isOption :: a -> bool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Example: | 
					
						
							|  |  |  |        isOption 1             // => false | 
					
						
							|  |  |  |        isOption (mkOption {}) // => true | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2013-10-23 18:20:39 +02:00
										 |  |  |   isOption = lib.isType "option"; | 
					
						
							| 
									
										
										
										
											2017-10-30 18:12:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |   /* Creates an Option attribute set. mkOption accepts an attribute set with the following keys:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      All keys default to `null` when not given. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Example: | 
					
						
							|  |  |  |        mkOption { }  // => { _type = "option"; } | 
					
						
							|  |  |  |        mkOption { defaultText = "foo"; } // => { _type = "option"; defaultText = "foo"; } | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2013-10-30 15:33:20 +01:00
										 |  |  |   mkOption = | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |     # Default value used when no definition is given in the configuration. | 
					
						
							|  |  |  |     default ? null, | 
					
						
							|  |  |  |     # Textual representation of the default, for the manual. | 
					
						
							|  |  |  |     defaultText ? null, | 
					
						
							|  |  |  |     # Example value used in the manual. | 
					
						
							|  |  |  |     example ? null, | 
					
						
							|  |  |  |     # String describing the option. | 
					
						
							|  |  |  |     description ? null, | 
					
						
							| 
									
										
										
										
											2019-08-26 02:01:49 +02:00
										 |  |  |     # Related packages used in the manual (see `genRelatedPackages` in ../nixos/lib/make-options-doc/default.nix). | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |     relatedPackages ? null, | 
					
						
							|  |  |  |     # Option type, providing type-checking and value merging. | 
					
						
							|  |  |  |     type ? null, | 
					
						
							|  |  |  |     # Function that converts the option value to something else. | 
					
						
							|  |  |  |     apply ? null, | 
					
						
							|  |  |  |     # Whether the option is for NixOS developers only. | 
					
						
							|  |  |  |     internal ? null, | 
					
						
							|  |  |  |     # Whether the option shows up in the manual. | 
					
						
							|  |  |  |     visible ? null, | 
					
						
							|  |  |  |     # Whether the option can be set only once | 
					
						
							|  |  |  |     readOnly ? null, | 
					
						
							| 
									
										
										
										
											2019-03-07 21:28:09 +02:00
										 |  |  |     # Deprecated, used by types.optionSet. | 
					
						
							|  |  |  |     options ? null | 
					
						
							| 
									
										
										
										
											2013-10-30 15:33:20 +01:00
										 |  |  |     } @ attrs: | 
					
						
							|  |  |  |     attrs // { _type = "option"; }; | 
					
						
							| 
									
										
										
										
											2009-05-27 20:25:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |   /* Creates an Option attribute set for a boolean value option i.e an
 | 
					
						
							|  |  |  |      option to be toggled on or off: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Example: | 
					
						
							|  |  |  |        mkEnableOption "foo" | 
					
						
							|  |  |  |        => { _type = "option"; default = false; description = "Whether to enable foo."; example = true; type = { ... }; } | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  |   mkEnableOption = | 
					
						
							|  |  |  |     # Name for the created option | 
					
						
							|  |  |  |     name: mkOption { | 
					
						
							| 
									
										
										
										
											2013-07-18 15:13:42 -04:00
										 |  |  |     default = false; | 
					
						
							|  |  |  |     example = true; | 
					
						
							| 
									
										
										
										
											2013-10-17 14:29:51 +02:00
										 |  |  |     description = "Whether to enable ${name}."; | 
					
						
							| 
									
										
										
										
											2013-07-18 15:13:42 -04:00
										 |  |  |     type = lib.types.bool; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |   /* This option accepts anything, but it does not produce any result.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      This is useful for sharing a module across different module sets | 
					
						
							|  |  |  |      without having to implement similar features as long as the | 
					
						
							|  |  |  |      values of the options are not accessed. */ | 
					
						
							| 
									
										
										
										
											2014-12-21 14:50:46 +01:00
										 |  |  |   mkSinkUndeclaredOptions = attrs: mkOption ({ | 
					
						
							|  |  |  |     internal = true; | 
					
						
							|  |  |  |     visible = false; | 
					
						
							|  |  |  |     default = false; | 
					
						
							|  |  |  |     description = "Sink for option definitions."; | 
					
						
							|  |  |  |     type = mkOptionType { | 
					
						
							|  |  |  |       name = "sink"; | 
					
						
							|  |  |  |       check = x: true; | 
					
						
							|  |  |  |       merge = loc: defs: false; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     apply = x: throw "Option value is not readable because the option is not declared."; | 
					
						
							|  |  |  |   } // attrs); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |   mergeDefaultOption = loc: defs: | 
					
						
							|  |  |  |     let list = getValues defs; in | 
					
						
							| 
									
										
										
										
											2012-08-13 14:19:31 -04:00
										 |  |  |     if length list == 1 then head list | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |     else if all isFunction list then x: mergeDefaultOption loc (map (f: f x) list) | 
					
						
							| 
									
										
										
										
											2009-05-19 14:54:41 +00:00
										 |  |  |     else if all isList list then concatLists list | 
					
						
							| 
									
										
										
										
											2015-07-23 17:19:21 +02:00
										 |  |  |     else if all isAttrs list then foldl' lib.mergeAttrs {} list | 
					
						
							|  |  |  |     else if all isBool list then foldl' lib.or false list | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |     else if all isString list then lib.concatStrings list | 
					
						
							|  |  |  |     else if all isInt list && all (x: x == head list) list then head list | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |     else throw "Cannot merge definitions of `${showOption loc}' given in ${showFiles (getFiles defs)}."; | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |   mergeOneOption = loc: defs: | 
					
						
							|  |  |  |     if defs == [] then abort "This case should never happen." | 
					
						
							|  |  |  |     else if length defs != 1 then | 
					
						
							| 
									
										
										
										
											2019-06-05 02:50:49 +03:00
										 |  |  |       throw "The unique option `${showOption loc}' is defined multiple times, in:\n - ${concatStringsSep "\n - " (getFiles defs)}." | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |     else (head defs).value; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 18:04:27 +02:00
										 |  |  |   /* "Merge" option definitions by checking that they all have the same value. */ | 
					
						
							|  |  |  |   mergeEqualOption = loc: defs: | 
					
						
							|  |  |  |     if defs == [] then abort "This case should never happen." | 
					
						
							| 
									
										
										
										
											2015-07-23 17:19:21 +02:00
										 |  |  |     else foldl' (val: def: | 
					
						
							| 
									
										
										
										
											2015-06-15 18:04:27 +02:00
										 |  |  |       if def.value != val then | 
					
						
							|  |  |  |         throw "The option `${showOption loc}' has conflicting definitions, in ${showFiles (getFiles defs)}." | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         val) (head defs).value defs; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |   /* Extracts values of all "value" keys of the given list.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: getValues :: [ { value :: a } ] -> [a] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Example: | 
					
						
							|  |  |  |        getValues [ { value = 1; } { value = 2; } ] // => [ 1 2 ] | 
					
						
							|  |  |  |        getValues [ ]                               // => [ ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |   getValues = map (x: x.value); | 
					
						
							| 
									
										
										
										
											2017-10-30 18:12:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |   /* Extracts values of all "file" keys of the given list
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: getFiles :: [ { file :: a } ] -> [a] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Example: | 
					
						
							|  |  |  |        getFiles [ { file = "file1"; } { file = "file2"; } ] // => [ "file1" "file2" ] | 
					
						
							|  |  |  |        getFiles [ ]                                         // => [ ] | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |   getFiles = map (x: x.file); | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-11 16:03:38 +00:00
										 |  |  |   # Generate documentation template from the list of option declaration like | 
					
						
							|  |  |  |   # the set generated with filterOptionSets. | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |   optionAttrSetToDocList = optionAttrSetToDocList' []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   optionAttrSetToDocList' = prefix: options: | 
					
						
							| 
									
										
										
										
											2015-07-23 16:32:52 +02:00
										 |  |  |     concatMap (opt: | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |       let | 
					
						
							|  |  |  |         docOption = rec { | 
					
						
							| 
									
										
										
										
											2018-02-11 22:04:09 +00:00
										 |  |  |           loc = opt.loc; | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |           name = showOption opt.loc; | 
					
						
							| 
									
										
										
										
											2019-02-22 00:05:58 +00:00
										 |  |  |           description = opt.description or (lib.warn "Option `${name}' has no description." "This option has no description."); | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |           declarations = filter (x: x != unknownModule) opt.declarations; | 
					
						
							|  |  |  |           internal = opt.internal or false; | 
					
						
							|  |  |  |           visible = opt.visible or true; | 
					
						
							| 
									
										
										
										
											2015-07-30 13:36:57 +02:00
										 |  |  |           readOnly = opt.readOnly or false; | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |           type = opt.type.description or null; | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-04-20 21:57:33 +00:00
										 |  |  |         // 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; }; | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         subOptions = | 
					
						
							|  |  |  |           let ss = opt.type.getSubOptions opt.loc; | 
					
						
							|  |  |  |           in if ss != {} then optionAttrSetToDocList' opt.loc ss else []; | 
					
						
							|  |  |  |       in | 
					
						
							| 
									
										
										
										
											2020-03-19 01:13:27 +01:00
										 |  |  |         [ docOption ] ++ optionals docOption.visible subOptions) (collect isOption options); | 
					
						
							| 
									
										
										
										
											2009-06-11 16:03:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-12 11:07:49 +00:00
										 |  |  |   /* This function recursively removes all derivation attributes from
 | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |      `x` except for the `name` attribute. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      This is to make the generation of `options.xml` much more | 
					
						
							|  |  |  |      efficient: the XML representation of derivations is very large | 
					
						
							|  |  |  |      (on the order of megabytes) and is not actually used by the | 
					
						
							|  |  |  |      manual generator. | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2013-10-17 14:29:51 +02:00
										 |  |  |   scrubOptionValue = x: | 
					
						
							| 
									
										
										
										
											2013-10-30 16:19:07 +01:00
										 |  |  |     if isDerivation x then | 
					
						
							|  |  |  |       { type = "derivation"; drvPath = x.name; outPath = x.name; name = x.name; } | 
					
						
							| 
									
										
										
										
											2010-05-12 11:07:49 +00:00
										 |  |  |     else if isList x then map scrubOptionValue x | 
					
						
							| 
									
										
										
										
											2010-06-01 14:24:16 +00:00
										 |  |  |     else if isAttrs x then mapAttrs (n: v: scrubOptionValue v) (removeAttrs x ["_args"]) | 
					
						
							| 
									
										
										
										
											2010-05-12 11:07:49 +00:00
										 |  |  |     else x; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-05 10:14:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |   /* For use in the `example` option attribute. It causes the given
 | 
					
						
							|  |  |  |      text to be included verbatim in documentation. This is necessary | 
					
						
							|  |  |  |      for example values that are not simple values, e.g., functions. | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2011-09-05 10:14:24 +00:00
										 |  |  |   literalExample = text: { _type = "literalExample"; inherit text; }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |   # Helper functions. | 
					
						
							| 
									
										
										
										
											2011-09-05 10:14:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |   /* Convert an option, described as a list of the option parts in to a
 | 
					
						
							|  |  |  |      safe, human readable version. | 
					
						
							| 
									
										
										
										
											2018-03-05 09:54:21 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 21:31:35 +01:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        (showOption ["foo" "bar" "baz"]) == "foo.bar.baz" | 
					
						
							|  |  |  |        (showOption ["foo" "bar.baz" "tux"]) == "foo.\"bar.baz\".tux" | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-03-05 09:54:21 -05:00
										 |  |  |   showOption = parts: let | 
					
						
							|  |  |  |     escapeOptionPart = part: | 
					
						
							|  |  |  |       let | 
					
						
							|  |  |  |         escaped = lib.strings.escapeNixString part; | 
					
						
							|  |  |  |       in if escaped == "\"${part}\"" | 
					
						
							|  |  |  |          then part | 
					
						
							|  |  |  |          else escaped; | 
					
						
							|  |  |  |     in (concatStringsSep ".") (map escapeOptionPart parts); | 
					
						
							| 
									
										
										
										
											2013-10-28 19:48:30 +01:00
										 |  |  |   showFiles = files: concatStringsSep " and " (map (f: "`${f}'") files); | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |   unknownModule = "<unknown-file>"; | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-24 10:57:41 +00:00
										 |  |  | } |