| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  | # Definitions related to run-time type checking.  Used in particular | 
					
						
							|  |  |  |  | # to type-check NixOS configurations. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-30 19:12:25 +01:00
										 |  |  |  | with import ./lists.nix; | 
					
						
							|  |  |  |  | with import ./attrsets.nix; | 
					
						
							|  |  |  |  | with import ./options.nix; | 
					
						
							|  |  |  |  | with import ./trivial.nix; | 
					
						
							|  |  |  |  | with import ./strings.nix; | 
					
						
							| 
									
										
										
										
											2015-08-17 17:55:35 +00:00
										 |  |  |  | with {inherit (import ./modules.nix) mergeDefinitions filterOverrides; }; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-12 23:01:47 +01:00
										 |  |  |  | rec { | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-13 15:05:30 +01:00
										 |  |  |  |   isType = type: x: (x._type or "") == type; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-19 17:19:39 +00:00
										 |  |  |  |   setType = typeName: value: value // { | 
					
						
							|  |  |  |  |     _type = typeName; | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-14 02:41:13 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |   # Default type merging function | 
					
						
							|  |  |  |  |   # takes two type functors and return the merged type | 
					
						
							|  |  |  |  |   defaultTypeMerge = f: f': | 
					
						
							|  |  |  |  |     let wrapped = f.wrapped.typeMerge f'.wrapped.functor; | 
					
						
							|  |  |  |  |         payload = f.binOp f.payload f'.payload; | 
					
						
							|  |  |  |  |     in | 
					
						
							|  |  |  |  |     # cannot merge different types | 
					
						
							|  |  |  |  |     if f.name != f'.name | 
					
						
							|  |  |  |  |        then null | 
					
						
							|  |  |  |  |     # simple types | 
					
						
							|  |  |  |  |     else if    (f.wrapped == null && f'.wrapped == null) | 
					
						
							|  |  |  |  |             && (f.payload == null && f'.payload == null) | 
					
						
							|  |  |  |  |        then f.type | 
					
						
							|  |  |  |  |     # composed types | 
					
						
							|  |  |  |  |     else if (f.wrapped != null && f'.wrapped != null) && (wrapped != null) | 
					
						
							|  |  |  |  |        then f.type wrapped | 
					
						
							|  |  |  |  |     # value types | 
					
						
							|  |  |  |  |     else if (f.payload != null && f'.payload != null) && (payload != null) | 
					
						
							|  |  |  |  |        then f.type payload | 
					
						
							|  |  |  |  |     else null; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   # Default type functor | 
					
						
							|  |  |  |  |   defaultFunctor = name: { | 
					
						
							|  |  |  |  |     inherit name; | 
					
						
							|  |  |  |  |     type    = types."${name}" or null; | 
					
						
							|  |  |  |  |     wrapped = null; | 
					
						
							|  |  |  |  |     payload = null; | 
					
						
							|  |  |  |  |     binOp   = a: b: null; | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-13 15:05:30 +01:00
										 |  |  |  |   isOptionType = isType "option-type"; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |   mkOptionType = | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |     { # Human-readable representation of the type, should be equivalent to | 
					
						
							|  |  |  |  |       # the type function name. | 
					
						
							| 
									
										
										
										
											2013-10-28 19:48:30 +01:00
										 |  |  |  |       name | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |     , # Description of the type, defined recursively by embedding the the wrapped type if any. | 
					
						
							|  |  |  |  |       description ? null | 
					
						
							| 
									
										
										
										
											2013-10-28 19:48:30 +01:00
										 |  |  |  |     , # Function applied to each definition that should return true if | 
					
						
							|  |  |  |  |       # its type-correct, false otherwise. | 
					
						
							|  |  |  |  |       check ? (x: true) | 
					
						
							|  |  |  |  |     , # Merge a list of definitions together into a single value. | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |       # This function is called with two arguments: the location of | 
					
						
							|  |  |  |  |       # the option in the configuration as a list of strings | 
					
						
							|  |  |  |  |       # (e.g. ["boot" "loader "grub" "enable"]), and a list of | 
					
						
							|  |  |  |  |       # definition values and locations (e.g. [ { file = "/foo.nix"; | 
					
						
							|  |  |  |  |       # value = 1; } { file = "/bar.nix"; value = 2 } ]). | 
					
						
							| 
									
										
										
										
											2013-10-28 19:48:30 +01:00
										 |  |  |  |       merge ? mergeDefaultOption | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |     , # Return a flat list of sub-options.  Used to generate | 
					
						
							|  |  |  |  |       # documentation. | 
					
						
							|  |  |  |  |       getSubOptions ? prefix: {} | 
					
						
							| 
									
										
										
										
											2014-08-29 16:42:44 +02:00
										 |  |  |  |     , # List of modules if any, or null if none. | 
					
						
							|  |  |  |  |       getSubModules ? null | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |     , # Function for building the same option type with a different list of | 
					
						
							| 
									
										
										
										
											2014-08-29 16:42:44 +02:00
										 |  |  |  |       # modules. | 
					
						
							|  |  |  |  |       substSubModules ? m: null | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |     , # Function that merge type declarations. | 
					
						
							|  |  |  |  |       # internal, takes a functor as argument and returns the merged type. | 
					
						
							|  |  |  |  |       # returning null means the type is not mergeable | 
					
						
							|  |  |  |  |       typeMerge ? defaultTypeMerge functor | 
					
						
							|  |  |  |  |     , # The type functor. | 
					
						
							|  |  |  |  |       # internal, representation of the type as an attribute set. | 
					
						
							|  |  |  |  |       #   name: name of the type | 
					
						
							|  |  |  |  |       #   type: type function. | 
					
						
							|  |  |  |  |       #   wrapped: the type wrapped in case of compound types. | 
					
						
							| 
									
										
										
										
											2017-03-11 17:39:40 -05:00
										 |  |  |  |       #   payload: values of the type, two payloads of the same type must be | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       #            combinable with the binOp binary operation. | 
					
						
							|  |  |  |  |       #   binOp: binary operation that merge two payloads of the same type. | 
					
						
							|  |  |  |  |       functor ? defaultFunctor name | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }: | 
					
						
							|  |  |  |  |     { _type = "option-type"; | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       inherit name check merge getSubOptions getSubModules substSubModules typeMerge functor; | 
					
						
							|  |  |  |  |       description = if description == null then name else description; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-14 02:41:13 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-07 01:58:56 +00:00
										 |  |  |  |   types = rec { | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  |     unspecified = mkOptionType { | 
					
						
							|  |  |  |  |       name = "unspecified"; | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     bool = mkOptionType { | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       name = "bool"; | 
					
						
							|  |  |  |  |       description = "boolean"; | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  |       check = isBool; | 
					
						
							| 
									
										
										
										
											2015-06-15 18:04:27 +02:00
										 |  |  |  |       merge = mergeEqualOption; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |     int = mkOptionType rec { | 
					
						
							|  |  |  |  |       name = "int"; | 
					
						
							|  |  |  |  |       description = "integer"; | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  |       check = isInt; | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |       merge = mergeOneOption; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-29 13:45:30 +01:00
										 |  |  |  |     str = mkOptionType { | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       name = "str"; | 
					
						
							|  |  |  |  |       description = "string"; | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  |       check = isString; | 
					
						
							| 
									
										
										
										
											2013-10-29 13:45:30 +01:00
										 |  |  |  |       merge = mergeOneOption; | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |     # Merge multiple definitions by concatenating them (with the given | 
					
						
							|  |  |  |  |     # separator between the values). | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |     separatedString = sep: mkOptionType rec { | 
					
						
							|  |  |  |  |       name = "separatedString"; | 
					
						
							|  |  |  |  |       description = "string"; | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  |       check = isString; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |       merge = loc: defs: concatStringsSep sep (getValues defs); | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       functor = (defaultFunctor name) // { | 
					
						
							|  |  |  |  |         payload = sep; | 
					
						
							|  |  |  |  |         binOp = sepLhs: sepRhs: | 
					
						
							|  |  |  |  |           if sepLhs == sepRhs then sepLhs | 
					
						
							|  |  |  |  |           else null; | 
					
						
							|  |  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2013-02-11 15:28:41 +01:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |     lines = separatedString "\n"; | 
					
						
							|  |  |  |  |     commas = separatedString ","; | 
					
						
							|  |  |  |  |     envVar = separatedString ":"; | 
					
						
							| 
									
										
										
										
											2013-10-28 16:14:15 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |     # Deprecated; should not be used because it quietly concatenates | 
					
						
							|  |  |  |  |     # strings, which is usually not what you want. | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |     string = separatedString ""; | 
					
						
							| 
									
										
										
										
											2009-11-07 01:58:56 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     attrs = mkOptionType { | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       name = "attrs"; | 
					
						
							|  |  |  |  |       description = "attribute set"; | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  |       check = isAttrs; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |       merge = loc: foldl' (res: def: mergeAttrs res def.value) {}; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     # derivation is a reserved keyword. | 
					
						
							|  |  |  |  |     package = mkOptionType { | 
					
						
							| 
									
										
										
										
											2016-02-17 20:24:22 +01:00
										 |  |  |  |       name = "package"; | 
					
						
							| 
									
										
										
										
											2015-08-06 19:55:42 +02:00
										 |  |  |  |       check = x: isDerivation x || isStorePath x; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |       merge = loc: defs: | 
					
						
							|  |  |  |  |         let res = mergeOneOption loc defs; | 
					
						
							| 
									
										
										
										
											2015-08-06 19:55:42 +02:00
										 |  |  |  |         in if isDerivation res then res else toDerivation res; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-12 20:03:14 +01:00
										 |  |  |  |     shellPackage = package // { | 
					
						
							|  |  |  |  |       check = x: (package.check x) && (hasAttr "shellPath" x); | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-25 17:19:07 +00:00
										 |  |  |  |     path = mkOptionType { | 
					
						
							|  |  |  |  |       name = "path"; | 
					
						
							|  |  |  |  |       # Hacky: there is no ‘isPath’ primop. | 
					
						
							| 
									
										
										
										
											2015-08-15 15:38:12 +02:00
										 |  |  |  |       check = x: builtins.substring 0 1 (toString x) == "/"; | 
					
						
							| 
									
										
										
										
											2013-10-28 19:48:30 +01:00
										 |  |  |  |       merge = mergeOneOption; | 
					
						
							| 
									
										
										
										
											2012-05-25 17:19:07 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-22 09:45:22 +03:00
										 |  |  |  |     # drop this in the future: | 
					
						
							| 
									
										
										
										
											2013-10-28 19:48:30 +01:00
										 |  |  |  |     list = builtins.trace "`types.list' is deprecated; use `types.listOf' instead" types.listOf; | 
					
						
							| 
									
										
										
										
											2013-08-22 09:45:22 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |     listOf = elemType: mkOptionType rec { | 
					
						
							|  |  |  |  |       name = "listOf"; | 
					
						
							|  |  |  |  |       description = "list of ${elemType.description}s"; | 
					
						
							| 
									
										
										
										
											2014-05-01 17:58:16 -04:00
										 |  |  |  |       check = isList; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |       merge = loc: defs: | 
					
						
							| 
									
										
										
										
											2016-05-25 11:02:38 +02:00
										 |  |  |  |         map (x: x.value) (filter (x: x ? value) (concatLists (imap (n: def: | 
					
						
							|  |  |  |  |           if isList def.value then | 
					
						
							|  |  |  |  |             imap (m: def': | 
					
						
							|  |  |  |  |               (mergeDefinitions | 
					
						
							|  |  |  |  |                 (loc ++ ["[definition ${toString n}-entry ${toString m}]"]) | 
					
						
							|  |  |  |  |                 elemType | 
					
						
							|  |  |  |  |                 [{ inherit (def) file; value = def'; }] | 
					
						
							|  |  |  |  |               ).optionalValue | 
					
						
							|  |  |  |  |             ) def.value | 
					
						
							|  |  |  |  |           else | 
					
						
							|  |  |  |  |             throw "The option value `${showOption loc}' in `${def.file}' is not a list.") defs))); | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |       getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]); | 
					
						
							| 
									
										
										
										
											2014-08-29 16:42:44 +02:00
										 |  |  |  |       getSubModules = elemType.getSubModules; | 
					
						
							|  |  |  |  |       substSubModules = m: listOf (elemType.substSubModules m); | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       functor = (defaultFunctor name) // { wrapped = elemType; }; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |     attrsOf = elemType: mkOptionType rec { | 
					
						
							|  |  |  |  |       name = "attrsOf"; | 
					
						
							|  |  |  |  |       description = "attribute set of ${elemType.description}s"; | 
					
						
							| 
									
										
										
										
											2014-05-01 18:13:06 -04:00
										 |  |  |  |       check = isAttrs; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |       merge = loc: defs: | 
					
						
							| 
									
										
										
										
											2014-05-01 18:13:06 -04:00
										 |  |  |  |         mapAttrs (n: v: v.value) (filterAttrs (n: v: v ? value) (zipAttrsWith (name: defs: | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |             (mergeDefinitions (loc ++ [name]) elemType defs).optionalValue | 
					
						
							| 
									
										
										
										
											2015-03-12 23:01:47 +01:00
										 |  |  |  |           ) | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |           # Push down position info. | 
					
						
							|  |  |  |  |           (map (def: listToAttrs (mapAttrsToList (n: def': | 
					
						
							| 
									
										
										
										
											2014-05-01 18:13:06 -04:00
										 |  |  |  |             { name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs))); | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |       getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]); | 
					
						
							| 
									
										
										
										
											2014-08-29 16:42:44 +02:00
										 |  |  |  |       getSubModules = elemType.getSubModules; | 
					
						
							|  |  |  |  |       substSubModules = m: attrsOf (elemType.substSubModules m); | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       functor = (defaultFunctor name) // { wrapped = elemType; }; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-14 02:41:13 +00:00
										 |  |  |  |     # List or attribute set of ... | 
					
						
							|  |  |  |  |     loaOf = elemType: | 
					
						
							|  |  |  |  |       let | 
					
						
							|  |  |  |  |         convertIfList = defIdx: def: | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |           if isList def.value then | 
					
						
							|  |  |  |  |             { inherit (def) file; | 
					
						
							|  |  |  |  |               value = listToAttrs ( | 
					
						
							|  |  |  |  |                 imap (elemIdx: elem: | 
					
						
							| 
									
										
										
										
											2014-02-20 10:40:49 -05:00
										 |  |  |  |                   { name = elem.name or "unnamed-${toString defIdx}.${toString elemIdx}"; | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |                     value = elem; | 
					
						
							|  |  |  |  |                   }) def.value); | 
					
						
							|  |  |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-06-14 02:41:13 +00:00
										 |  |  |  |           else | 
					
						
							|  |  |  |  |             def; | 
					
						
							|  |  |  |  |         listOnly = listOf elemType; | 
					
						
							|  |  |  |  |         attrOnly = attrsOf elemType; | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       in mkOptionType rec { | 
					
						
							|  |  |  |  |         name = "loaOf"; | 
					
						
							|  |  |  |  |         description = "list or attribute set of ${elemType.description}s"; | 
					
						
							| 
									
										
										
										
											2014-05-01 20:17:03 -04:00
										 |  |  |  |         check = x: isList x || isAttrs x; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |         merge = loc: defs: attrOnly.merge loc (imap convertIfList defs); | 
					
						
							|  |  |  |  |         getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]); | 
					
						
							| 
									
										
										
										
											2014-08-29 16:42:44 +02:00
										 |  |  |  |         getSubModules = elemType.getSubModules; | 
					
						
							|  |  |  |  |         substSubModules = m: loaOf (elemType.substSubModules m); | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |         functor = (defaultFunctor name) // { wrapped = elemType; }; | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2011-06-14 02:41:13 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-17 17:55:35 +00:00
										 |  |  |  |     # List or element of ... | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |     loeOf = elemType: mkOptionType rec { | 
					
						
							|  |  |  |  |       name = "loeOf"; | 
					
						
							|  |  |  |  |       description = "element or list of ${elemType.description}s"; | 
					
						
							| 
									
										
										
										
											2015-08-17 17:55:35 +00:00
										 |  |  |  |       check = x: isList x || elemType.check x; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |       merge = loc: defs: | 
					
						
							| 
									
										
										
										
											2015-08-17 17:55:35 +00:00
										 |  |  |  |         let | 
					
						
							|  |  |  |  |           defs' = filterOverrides defs; | 
					
						
							|  |  |  |  |           res = (head defs').value; | 
					
						
							|  |  |  |  |         in | 
					
						
							|  |  |  |  |         if isList res then concatLists (getValues defs') | 
					
						
							|  |  |  |  |         else if lessThan 1 (length defs') then | 
					
						
							|  |  |  |  |           throw "The option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}." | 
					
						
							|  |  |  |  |         else if !isString res then | 
					
						
							|  |  |  |  |           throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}." | 
					
						
							|  |  |  |  |         else res; | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       functor = (defaultFunctor name) // { wrapped = elemType; }; | 
					
						
							| 
									
										
										
										
											2015-08-17 17:55:35 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |     uniq = elemType: mkOptionType rec { | 
					
						
							|  |  |  |  |       name = "uniq"; | 
					
						
							|  |  |  |  |       inherit (elemType) description check; | 
					
						
							| 
									
										
										
										
											2013-10-28 19:48:30 +01:00
										 |  |  |  |       merge = mergeOneOption; | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |       getSubOptions = elemType.getSubOptions; | 
					
						
							| 
									
										
										
										
											2014-08-29 16:42:44 +02:00
										 |  |  |  |       getSubModules = elemType.getSubModules; | 
					
						
							|  |  |  |  |       substSubModules = m: uniq (elemType.substSubModules m); | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       functor = (defaultFunctor name) // { wrapped = elemType; }; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |     nullOr = elemType: mkOptionType rec { | 
					
						
							|  |  |  |  |       name = "nullOr"; | 
					
						
							|  |  |  |  |       description = "null or ${elemType.description}"; | 
					
						
							| 
									
										
										
										
											2015-12-04 07:22:57 +03:00
										 |  |  |  |       check = x: x == null || elemType.check x; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |       merge = loc: defs: | 
					
						
							| 
									
										
										
										
											2015-12-04 07:22:57 +03:00
										 |  |  |  |         let nrNulls = count (def: def.value == null) defs; in | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |         if nrNulls == length defs then null | 
					
						
							|  |  |  |  |         else if nrNulls != 0 then | 
					
						
							|  |  |  |  |           throw "The option `${showOption loc}' is defined both null and not null, in ${showFiles (getFiles defs)}." | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |         else elemType.merge loc defs; | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |       getSubOptions = elemType.getSubOptions; | 
					
						
							| 
									
										
										
										
											2014-08-29 16:42:44 +02:00
										 |  |  |  |       getSubModules = elemType.getSubModules; | 
					
						
							|  |  |  |  |       substSubModules = m: nullOr (elemType.substSubModules m); | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       functor = (defaultFunctor name) // { wrapped = elemType; }; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 12:08:05 -05:00
										 |  |  |  |     submodule = opts: | 
					
						
							| 
									
										
										
										
											2013-10-30 19:12:25 +01:00
										 |  |  |  |       let | 
					
						
							|  |  |  |  |         opts' = toList opts; | 
					
						
							|  |  |  |  |         inherit (import ./modules.nix) evalModules; | 
					
						
							|  |  |  |  |       in | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |       mkOptionType rec { | 
					
						
							|  |  |  |  |         name = "submodule"; | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  |         check = x: isAttrs x || isFunction x; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |         merge = loc: defs: | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |           let | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  |             coerce = def: if isFunction def then def else { config = def; }; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |             modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs; | 
					
						
							| 
									
										
										
										
											2014-05-05 16:30:51 -04:00
										 |  |  |  |           in (evalModules { | 
					
						
							|  |  |  |  |             inherit modules; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |             args.name = last loc; | 
					
						
							| 
									
										
										
										
											2014-05-05 16:30:51 -04:00
										 |  |  |  |             prefix = loc; | 
					
						
							|  |  |  |  |           }).config; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |         getSubOptions = prefix: (evalModules | 
					
						
							|  |  |  |  |           { modules = opts'; inherit prefix; | 
					
						
							| 
									
										
										
										
											2013-10-28 15:48:20 +01:00
										 |  |  |  |             # FIXME: hack to get shit to evaluate. | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |             args = { name = ""; }; }).options; | 
					
						
							| 
									
										
										
										
											2014-08-29 16:42:44 +02:00
										 |  |  |  |         getSubModules = opts'; | 
					
						
							|  |  |  |  |         substSubModules = m: submodule m; | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |         functor = (defaultFunctor name) // { | 
					
						
							|  |  |  |  |           # Merging of submodules is done as part of mergeOptionDecls, as we have to annotate | 
					
						
							|  |  |  |  |           # each submodule with its location. | 
					
						
							|  |  |  |  |           payload = []; | 
					
						
							|  |  |  |  |           binOp = lhs: rhs: []; | 
					
						
							|  |  |  |  |         }; | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |     enum = values: | 
					
						
							|  |  |  |  |       let | 
					
						
							|  |  |  |  |         show = v: | 
					
						
							|  |  |  |  |                if builtins.isString v then ''"${v}"'' | 
					
						
							|  |  |  |  |           else if builtins.isInt v then builtins.toString v | 
					
						
							|  |  |  |  |           else ''<${builtins.typeOf v}>''; | 
					
						
							|  |  |  |  |       in | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       mkOptionType rec { | 
					
						
							|  |  |  |  |         name = "enum"; | 
					
						
							|  |  |  |  |         description = "one of ${concatMapStringsSep ", " show values}"; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |         check = flip elem values; | 
					
						
							|  |  |  |  |         merge = mergeOneOption; | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |         functor = (defaultFunctor name) // { payload = values; binOp = a: b: unique (a ++ b); }; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2014-05-01 11:30:20 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |     either = t1: t2: mkOptionType rec { | 
					
						
							|  |  |  |  |       name = "either"; | 
					
						
							|  |  |  |  |       description = "${t1.description} or ${t2.description}"; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |       check = x: t1.check x || t2.check x; | 
					
						
							| 
									
										
										
										
											2016-11-07 08:34:06 +09:00
										 |  |  |  |       merge = loc: defs: | 
					
						
							|  |  |  |  |         let | 
					
						
							|  |  |  |  |           defList = map (d: d.value) defs; | 
					
						
							|  |  |  |  |         in | 
					
						
							|  |  |  |  |           if   all (x: t1.check x) defList | 
					
						
							|  |  |  |  |                then t1.merge loc defs | 
					
						
							|  |  |  |  |           else if all (x: t2.check x) defList | 
					
						
							|  |  |  |  |                then t2.merge loc defs | 
					
						
							|  |  |  |  |           else mergeOneOption loc defs; | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       typeMerge = f': | 
					
						
							|  |  |  |  |         let mt1 = t1.typeMerge (elemAt f'.wrapped 0).functor; | 
					
						
							|  |  |  |  |             mt2 = t2.typeMerge (elemAt f'.wrapped 1).functor; | 
					
						
							|  |  |  |  |         in | 
					
						
							|  |  |  |  |            if (name == f'.name) && (mt1 != null) && (mt2 != null) | 
					
						
							|  |  |  |  |            then functor.type mt1 mt2 | 
					
						
							|  |  |  |  |            else null; | 
					
						
							|  |  |  |  |       functor = (defaultFunctor name) // { wrapped = [ t1 t2 ]; }; | 
					
						
							| 
									
										
										
										
											2016-03-01 20:47:08 +01:00
										 |  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2014-08-19 13:13:51 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-14 04:14:01 +03:00
										 |  |  |  |     coercedTo = coercedType: coerceFunc: finalType: | 
					
						
							|  |  |  |  |       assert coercedType.getSubModules == null; | 
					
						
							|  |  |  |  |       mkOptionType rec { | 
					
						
							|  |  |  |  |         name = "coercedTo"; | 
					
						
							|  |  |  |  |         description = "${finalType.description} or ${coercedType.description}"; | 
					
						
							|  |  |  |  |         check = x: finalType.check x || coercedType.check x; | 
					
						
							|  |  |  |  |         merge = loc: defs: | 
					
						
							|  |  |  |  |           let | 
					
						
							|  |  |  |  |             coerceVal = val: | 
					
						
							|  |  |  |  |               if finalType.check val then val | 
					
						
							|  |  |  |  |               else let | 
					
						
							|  |  |  |  |                 coerced = coerceFunc val; | 
					
						
							|  |  |  |  |               in assert finalType.check coerced; coerced; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           in finalType.merge loc (map (def: def // { value = coerceVal def.value; }) defs); | 
					
						
							|  |  |  |  |         getSubOptions = finalType.getSubOptions; | 
					
						
							|  |  |  |  |         getSubModules = finalType.getSubModules; | 
					
						
							|  |  |  |  |         substSubModules = m: coercedTo coercedType coerceFunc (finalType.substSubModules m); | 
					
						
							|  |  |  |  |         typeMerge = t1: t2: null; | 
					
						
							|  |  |  |  |         functor = (defaultFunctor name) // { wrapped = finalType; }; | 
					
						
							|  |  |  |  |       }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  |     # Obsolete alternative to configOf.  It takes its option | 
					
						
							|  |  |  |  |     # declarations from the ‘options’ attribute of containing option | 
					
						
							|  |  |  |  |     # declaration. | 
					
						
							|  |  |  |  |     optionSet = mkOptionType { | 
					
						
							| 
									
										
										
										
											2016-09-07 10:03:32 +09:00
										 |  |  |  |       name = builtins.trace "types.optionSet is deprecated; use types.submodule instead" "optionSet"; | 
					
						
							|  |  |  |  |       description = "option set"; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-30 15:33:20 +01:00
										 |  |  |  |     # Augment the given type with an additional type check function. | 
					
						
							|  |  |  |  |     addCheck = elemType: check: elemType // { check = x: elemType.check x && check x; }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |   }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | } |