| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | rec { | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-13 15:05:30 +01:00
										 |  |  |  |   isOptionType = isType "option-type"; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |   mkOptionType = | 
					
						
							| 
									
										
										
										
											2013-10-28 19:48:30 +01:00
										 |  |  |  |     { # Human-readable representation of the type. | 
					
						
							|  |  |  |  |       name | 
					
						
							|  |  |  |  |     , # 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 | 
					
						
							|  |  |  |  |     , # Return a flat list of sub-options.  Used to generate | 
					
						
							|  |  |  |  |       # documentation. | 
					
						
							|  |  |  |  |       getSubOptions ? prefix: {} | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }: | 
					
						
							|  |  |  |  |     { _type = "option-type"; | 
					
						
							| 
									
										
										
										
											2013-10-28 19:48:30 +01:00
										 |  |  |  |       inherit name check merge getSubOptions; | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							|  |  |  |  |       name = "boolean"; | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  |       check = isBool; | 
					
						
							| 
									
										
										
										
											2013-10-30 19:12:25 +01:00
										 |  |  |  |       merge = loc: fold (x: y: x.value || y) false; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     int = mkOptionType { | 
					
						
							|  |  |  |  |       name = "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 { | 
					
						
							|  |  |  |  |       name = "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). | 
					
						
							|  |  |  |  |     separatedString = sep: mkOptionType { | 
					
						
							| 
									
										
										
										
											2013-02-11 15:28:41 +01:00
										 |  |  |  |       name = "string"; | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  |       check = isString; | 
					
						
							| 
									
										
										
										
											2013-10-30 19:12:25 +01:00
										 |  |  |  |       merge = loc: defs: concatStringsSep sep (getValues defs); | 
					
						
							| 
									
										
										
										
											2013-02-11 15:28:41 +01:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +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. | 
					
						
							|  |  |  |  |     string = separatedString ""; | 
					
						
							| 
									
										
										
										
											2009-11-07 01:58:56 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     attrs = mkOptionType { | 
					
						
							|  |  |  |  |       name = "attribute set"; | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  |       check = isAttrs; | 
					
						
							| 
									
										
										
										
											2013-10-30 19:12:25 +01:00
										 |  |  |  |       merge = loc: fold (def: mergeAttrs def.value) {}; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     # derivation is a reserved keyword. | 
					
						
							|  |  |  |  |     package = mkOptionType { | 
					
						
							|  |  |  |  |       name = "derivation"; | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  |       check = isDerivation; | 
					
						
							| 
									
										
										
										
											2013-10-28 19:48:30 +01:00
										 |  |  |  |       merge = mergeOneOption; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-25 17:19:07 +00:00
										 |  |  |  |     path = mkOptionType { | 
					
						
							|  |  |  |  |       name = "path"; | 
					
						
							|  |  |  |  |       # Hacky: there is no ‘isPath’ primop. | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  |       check = x: builtins.unsafeDiscardStringContext (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
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  |     listOf = elemType: mkOptionType { | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |       name = "list of ${elemType.name}s"; | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  |       check = value: isList value && all elemType.check value; | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |       merge = loc: defs: | 
					
						
							|  |  |  |  |         concatLists (imap (n: def: imap (m: def': | 
					
						
							|  |  |  |  |           elemType.merge (loc ++ ["[${toString n}-${toString m}]"]) | 
					
						
							|  |  |  |  |             [{ inherit (def) file; value = def'; }]) def.value) defs); | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |       getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]); | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     attrsOf = elemType: mkOptionType { | 
					
						
							| 
									
										
										
										
											2011-04-27 18:41:27 +00:00
										 |  |  |  |       name = "attribute set of ${elemType.name}s"; | 
					
						
							| 
									
										
										
										
											2013-10-30 19:12:25 +01:00
										 |  |  |  |       check = x: isAttrs x && all elemType.check (attrValues x); | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |       merge = loc: defs: | 
					
						
							|  |  |  |  |         zipAttrsWith (name: elemType.merge (loc ++ [name])) | 
					
						
							|  |  |  |  |           # Push down position info. | 
					
						
							|  |  |  |  |           (map (def: listToAttrs (mapAttrsToList (n: def': | 
					
						
							|  |  |  |  |             { name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs); | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |       getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]); | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							|  |  |  |  |       in mkOptionType { | 
					
						
							|  |  |  |  |         name = "list or attribute set of ${elemType.name}s"; | 
					
						
							|  |  |  |  |         check = x: | 
					
						
							|  |  |  |  |           if isList x       then listOnly.check x | 
					
						
							|  |  |  |  |           else if isAttrs x then attrOnly.check x | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  |           else false; | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |         merge = loc: defs: attrOnly.merge loc (imap convertIfList defs); | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |         getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]); | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2011-06-14 02:41:13 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     uniq = elemType: mkOptionType { | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |       inherit (elemType) name check; | 
					
						
							| 
									
										
										
										
											2013-10-28 19:48:30 +01:00
										 |  |  |  |       merge = mergeOneOption; | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |       getSubOptions = elemType.getSubOptions; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     nullOr = elemType: mkOptionType { | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  |       name = "null or ${elemType.name}"; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |       check = x: builtins.isNull x || elemType.check x; | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |       merge = loc: defs: | 
					
						
							|  |  |  |  |         let nrNulls = count (def: isNull def.value) defs; in | 
					
						
							|  |  |  |  |         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)}." | 
					
						
							|  |  |  |  |         else elemType.merge loc defs; | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |       getSubOptions = elemType.getSubOptions; | 
					
						
							| 
									
										
										
										
											2009-06-26 13:53:31 +00:00
										 |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-19 22:49:21 -05:00
										 |  |  |  |     functionTo = elemType: mkOptionType { | 
					
						
							|  |  |  |  |       name = "function that evaluates to a(n) ${elemType.name}"; | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  |       check = isFunction; | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |       merge = loc: defs: | 
					
						
							|  |  |  |  |         fnArgs: elemType.merge loc (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs); | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |       getSubOptions = elemType.getSubOptions; | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +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; }; | 
					
						
							| 
									
										
										
										
											2013-10-30 14:21:41 +01:00
										 |  |  |  |             modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs; | 
					
						
							| 
									
										
										
										
											2014-02-13 12:08:05 -05:00
										 |  |  |  |           in (evalModules { inherit modules; args.name = last loc; prefix = loc; }).config; | 
					
						
							| 
									
										
										
										
											2013-10-28 15:48:20 +01:00
										 |  |  |  |         getSubOptions = prefix: (evalModules | 
					
						
							|  |  |  |  |           { modules = opts'; inherit prefix; | 
					
						
							|  |  |  |  |             # FIXME: hack to get shit to evaluate. | 
					
						
							| 
									
										
										
										
											2014-02-13 12:08:05 -05:00
										 |  |  |  |             args = { name = ""; }; }).options; | 
					
						
							| 
									
										
										
										
											2013-10-28 14:25:58 +01:00
										 |  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2013-10-28 00:56:22 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-01 11:30:20 -04:00
										 |  |  |  |     enum = values: mkOptionType { | 
					
						
							| 
									
										
										
										
											2014-05-01 11:46:44 -04:00
										 |  |  |  |       name = "one of ${concatStringsSep ", " values}"; | 
					
						
							| 
									
										
										
										
											2014-05-01 11:30:20 -04:00
										 |  |  |  |       check = flip elem values; | 
					
						
							|  |  |  |  |       merge = mergeOneOption; | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-19 13:13:51 +02:00
										 |  |  |  |     either = t1: t2: mkOptionType { | 
					
						
							|  |  |  |  |       name = "${t1.name} or ${t2.name}"; | 
					
						
							|  |  |  |  |       check = x: t1.check x || t2.check x; | 
					
						
							|  |  |  |  |       merge = mergeOneOption; | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							|  |  |  |  |       name = /* builtins.trace "types.optionSet is deprecated; use types.submodule instead" */ "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
										 |  |  |  |   }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | } |