| 
									
										
										
										
											2016-11-17 22:29:32 +01:00
										 |  |  |  | /* Functions that generate widespread file
 | 
					
						
							| 
									
										
										
										
											2016-11-06 01:51:13 +01:00
										 |  |  |  |  * formats from nix data structures. | 
					
						
							| 
									
										
										
										
											2016-11-17 22:29:32 +01:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * They all follow a similar interface: | 
					
						
							|  |  |  |  |  * generator { config-attrs } data | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-03-26 17:28:17 +02:00
										 |  |  |  |  * `config-attrs` are “holes” in the generators | 
					
						
							|  |  |  |  |  * with sensible default implementations that | 
					
						
							|  |  |  |  |  * can be overwritten. The default implementations | 
					
						
							|  |  |  |  |  * are mostly generators themselves, called with | 
					
						
							|  |  |  |  |  * their respective default values; they can be reused. | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-11-06 01:51:13 +01:00
										 |  |  |  |  * Tests can be found in ./tests.nix | 
					
						
							| 
									
										
										
										
											2016-11-17 22:29:32 +01:00
										 |  |  |  |  * Documentation in the manual, #sec-generators | 
					
						
							| 
									
										
										
										
											2016-11-06 01:51:13 +01:00
										 |  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-07-28 20:05:35 -04:00
										 |  |  |  | { lib }: | 
					
						
							|  |  |  |  | with (lib).trivial; | 
					
						
							| 
									
										
										
										
											2016-11-06 01:51:13 +01:00
										 |  |  |  | let | 
					
						
							| 
									
										
										
										
											2017-07-28 20:05:35 -04:00
										 |  |  |  |   libStr = lib.strings; | 
					
						
							|  |  |  |  |   libAttr = lib.attrsets; | 
					
						
							| 
									
										
										
										
											2016-11-06 01:51:13 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-31 14:02:19 -05:00
										 |  |  |  |   inherit (lib) isFunction; | 
					
						
							| 
									
										
										
										
											2016-11-06 01:51:13 +01:00
										 |  |  |  | in | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 14:14:24 +01:00
										 |  |  |  | rec { | 
					
						
							| 
									
										
										
										
											2016-11-06 01:51:13 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-26 17:28:17 +02:00
										 |  |  |  |   ## -- HELPER FUNCTIONS & DEFAULTS -- | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-26 17:31:05 +02:00
										 |  |  |  |   /* Convert a value to a sensible default string representation.
 | 
					
						
							|  |  |  |  |    * The builtin `toString` function has some strange defaults, | 
					
						
							|  |  |  |  |    * suitable for bash scripts but not much else. | 
					
						
							|  |  |  |  |    */ | 
					
						
							|  |  |  |  |   mkValueStringDefault = {}: v: with builtins; | 
					
						
							|  |  |  |  |     let err = t: v: abort | 
					
						
							|  |  |  |  |           ("generators.mkValueStringDefault: " + | 
					
						
							|  |  |  |  |            "${t} not supported: ${toPretty {} v}"); | 
					
						
							|  |  |  |  |     in   if isInt      v then toString v | 
					
						
							|  |  |  |  |     # we default to not quoting strings | 
					
						
							|  |  |  |  |     else if isString   v then v | 
					
						
							|  |  |  |  |     # isString returns "1", which is not a good default | 
					
						
							|  |  |  |  |     else if true  ==   v then "true" | 
					
						
							|  |  |  |  |     # here it returns to "", which is even less of a good default | 
					
						
							|  |  |  |  |     else if false ==   v then "false" | 
					
						
							|  |  |  |  |     else if null  ==   v then "null" | 
					
						
							|  |  |  |  |     # if you have lists you probably want to replace this | 
					
						
							|  |  |  |  |     else if isList     v then err "lists" v | 
					
						
							|  |  |  |  |     # same as for lists, might want to replace | 
					
						
							|  |  |  |  |     else if isAttrs    v then err "attrsets" v | 
					
						
							| 
									
										
										
										
											2020-01-23 01:07:02 +01:00
										 |  |  |  |     # functions can’t be printed of course | 
					
						
							| 
									
										
										
										
											2018-03-26 17:31:05 +02:00
										 |  |  |  |     else if isFunction v then err "functions" v | 
					
						
							| 
									
										
										
										
											2019-12-13 00:24:30 +01:00
										 |  |  |  |     # Floats currently can't be converted to precise strings, | 
					
						
							|  |  |  |  |     # condition warning on nix version once this isn't a problem anymore | 
					
						
							|  |  |  |  |     # See https://github.com/NixOS/nix/pull/3480 | 
					
						
							|  |  |  |  |     else if isFloat    v then libStr.floatToString v | 
					
						
							| 
									
										
										
										
											2018-03-26 17:31:05 +02:00
										 |  |  |  |     else err "this value is" (toString v); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-04 22:11:24 +01:00
										 |  |  |  |   /* Generate a line of key k and value v, separated by
 | 
					
						
							|  |  |  |  |    * character sep. If sep appears in k, it is escaped. | 
					
						
							|  |  |  |  |    * Helper for synaxes with different separators. | 
					
						
							|  |  |  |  |    * | 
					
						
							| 
									
										
										
										
											2017-11-09 15:58:14 +01:00
										 |  |  |  |    * mkValueString specifies how values should be formatted. | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * mkKeyValueDefault {} ":" "f:oo" "bar" | 
					
						
							| 
									
										
										
										
											2016-12-04 22:11:24 +01:00
										 |  |  |  |    * > "f\:oo:bar" | 
					
						
							|  |  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2017-11-09 15:58:14 +01:00
										 |  |  |  |   mkKeyValueDefault = { | 
					
						
							| 
									
										
										
										
											2018-03-26 17:31:05 +02:00
										 |  |  |  |     mkValueString ? mkValueStringDefault {} | 
					
						
							| 
									
										
										
										
											2017-11-09 15:58:14 +01:00
										 |  |  |  |   }: sep: k: v: | 
					
						
							|  |  |  |  |     "${libStr.escape [sep] k}${sep}${mkValueString v}"; | 
					
						
							| 
									
										
										
										
											2016-12-04 22:11:24 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-26 17:28:17 +02:00
										 |  |  |  |   ## -- FILE FORMAT GENERATORS -- | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-04 22:11:24 +01:00
										 |  |  |  |   /* Generate a key-value-style config file from an attrset.
 | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * mkKeyValue is the same as in toINI. | 
					
						
							|  |  |  |  |    */ | 
					
						
							|  |  |  |  |   toKeyValue = { | 
					
						
							| 
									
										
										
										
											2020-03-10 02:38:28 +01:00
										 |  |  |  |     mkKeyValue ? mkKeyValueDefault {} "=", | 
					
						
							|  |  |  |  |     listsAsDuplicateKeys ? false | 
					
						
							|  |  |  |  |   }: | 
					
						
							|  |  |  |  |   let mkLine = k: v: mkKeyValue k v + "\n"; | 
					
						
							|  |  |  |  |       mkLines = if listsAsDuplicateKeys | 
					
						
							|  |  |  |  |         then k: v: map (mkLine k) (if lib.isList v then v else [v]) | 
					
						
							|  |  |  |  |         else k: v: [ (mkLine k v) ]; | 
					
						
							|  |  |  |  |   in attrs: libStr.concatStrings (lib.concatLists (libAttr.mapAttrsToList mkLines attrs)); | 
					
						
							| 
									
										
										
										
											2016-12-04 22:11:24 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* Generate an INI-style config file from an
 | 
					
						
							| 
									
										
										
										
											2016-11-06 01:51:13 +01:00
										 |  |  |  |    * attrset of sections to an attrset of key-value pairs. | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * generators.toINI {} { | 
					
						
							|  |  |  |  |    *   foo = { hi = "${pkgs.hello}"; ciao = "bar"; }; | 
					
						
							|  |  |  |  |    *   baz = { "also, integers" = 42; }; | 
					
						
							|  |  |  |  |    * } | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    *> [baz] | 
					
						
							|  |  |  |  |    *> also, integers=42 | 
					
						
							|  |  |  |  |    *> | 
					
						
							|  |  |  |  |    *> [foo] | 
					
						
							|  |  |  |  |    *> ciao=bar | 
					
						
							|  |  |  |  |    *> hi=/nix/store/y93qql1p5ggfnaqjjqhxcw0vqw95rlz0-hello-2.10 | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * The mk* configuration attributes can generically change | 
					
						
							|  |  |  |  |    * the way sections and key-value strings are generated. | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * For more examples see the test cases in ./tests.nix. | 
					
						
							|  |  |  |  |    */ | 
					
						
							|  |  |  |  |   toINI = { | 
					
						
							|  |  |  |  |     # apply transformations (e.g. escapes) to section names | 
					
						
							|  |  |  |  |     mkSectionName ? (name: libStr.escape [ "[" "]" ] name), | 
					
						
							|  |  |  |  |     # format a setting line from key and value | 
					
						
							| 
									
										
										
										
											2020-03-10 02:38:28 +01:00
										 |  |  |  |     mkKeyValue    ? mkKeyValueDefault {} "=", | 
					
						
							|  |  |  |  |     # allow lists as values for duplicate keys | 
					
						
							|  |  |  |  |     listsAsDuplicateKeys ? false | 
					
						
							| 
									
										
										
										
											2016-11-06 01:51:13 +01:00
										 |  |  |  |   }: attrsOfAttrs: | 
					
						
							|  |  |  |  |     let | 
					
						
							|  |  |  |  |         # map function to string for each key val | 
					
						
							|  |  |  |  |         mapAttrsToStringsSep = sep: mapFn: attrs: | 
					
						
							|  |  |  |  |           libStr.concatStringsSep sep | 
					
						
							|  |  |  |  |             (libAttr.mapAttrsToList mapFn attrs); | 
					
						
							|  |  |  |  |         mkSection = sectName: sectValues: ''
 | 
					
						
							|  |  |  |  |           [${mkSectionName sectName}] | 
					
						
							| 
									
										
										
										
											2020-03-10 02:38:28 +01:00
										 |  |  |  |         '' + toKeyValue { inherit mkKeyValue listsAsDuplicateKeys; } sectValues;
 | 
					
						
							| 
									
										
										
										
											2016-11-06 01:51:13 +01:00
										 |  |  |  |     in | 
					
						
							|  |  |  |  |       # map input to ini sections | 
					
						
							|  |  |  |  |       mapAttrsToStringsSep "\n" mkSection attrsOfAttrs; | 
					
						
							| 
									
										
										
										
											2016-11-06 14:14:24 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-05 18:59:32 +01:00
										 |  |  |  |   /* Generate a git-config file from an attrset.
 | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * It has two major differences from the regular INI format: | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * 1. values are indented with tabs | 
					
						
							|  |  |  |  |    * 2. sections can have sub-sections | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * generators.toGitINI { | 
					
						
							|  |  |  |  |    *   url."ssh://git@github.com/".insteadOf = "https://github.com"; | 
					
						
							|  |  |  |  |    *   user.name = "edolstra"; | 
					
						
							|  |  |  |  |    * } | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    *> [url "ssh://git@github.com/"] | 
					
						
							|  |  |  |  |    *>   insteadOf = https://github.com/ | 
					
						
							|  |  |  |  |    *> | 
					
						
							|  |  |  |  |    *> [user] | 
					
						
							|  |  |  |  |    *>   name = edolstra | 
					
						
							|  |  |  |  |    */ | 
					
						
							|  |  |  |  |   toGitINI = attrs: | 
					
						
							|  |  |  |  |     with builtins; | 
					
						
							|  |  |  |  |     let | 
					
						
							|  |  |  |  |       mkSectionName = name: | 
					
						
							|  |  |  |  |         let | 
					
						
							|  |  |  |  |           containsQuote = libStr.hasInfix ''"'' name; | 
					
						
							|  |  |  |  |           sections = libStr.splitString "." name; | 
					
						
							|  |  |  |  |           section = head sections; | 
					
						
							|  |  |  |  |           subsections = tail sections; | 
					
						
							|  |  |  |  |           subsection = concatStringsSep "." subsections; | 
					
						
							|  |  |  |  |         in if containsQuote || subsections == [ ] then | 
					
						
							|  |  |  |  |           name | 
					
						
							|  |  |  |  |         else | 
					
						
							|  |  |  |  |           ''${section} "${subsection}"''; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       # generation for multiple ini values | 
					
						
							|  |  |  |  |       mkKeyValue = k: v: | 
					
						
							|  |  |  |  |         let mkKeyValue = mkKeyValueDefault { } " = " k; | 
					
						
							|  |  |  |  |         in concatStringsSep "\n" (map (kv: "\t" + mkKeyValue kv) (lib.toList v)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       # converts { a.b.c = 5; } to { "a.b".c = 5; } for toINI | 
					
						
							|  |  |  |  |       gitFlattenAttrs = let | 
					
						
							|  |  |  |  |         recurse = path: value: | 
					
						
							|  |  |  |  |           if isAttrs value then | 
					
						
							|  |  |  |  |             lib.mapAttrsToList (name: value: recurse ([ name ] ++ path) value) value | 
					
						
							|  |  |  |  |           else if length path > 1 then { | 
					
						
							|  |  |  |  |             ${concatStringsSep "." (lib.reverseList (tail path))}.${head path} = value; | 
					
						
							|  |  |  |  |           } else { | 
					
						
							|  |  |  |  |             ${head path} = value; | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  |       in attrs: lib.foldl lib.recursiveUpdate { } (lib.flatten (recurse [ ] attrs)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       toINI_ = toINI { inherit mkKeyValue mkSectionName; }; | 
					
						
							|  |  |  |  |     in | 
					
						
							|  |  |  |  |       toINI_ (gitFlattenAttrs attrs); | 
					
						
							| 
									
										
										
										
											2016-11-06 14:14:24 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* Generates JSON from an arbitrary (non-function) value.
 | 
					
						
							|  |  |  |  |     * For more information see the documentation of the builtin. | 
					
						
							|  |  |  |  |     */ | 
					
						
							|  |  |  |  |   toJSON = {}: builtins.toJSON; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* YAML has been a strict superset of JSON since 1.2, so we
 | 
					
						
							|  |  |  |  |     * use toJSON. Before it only had a few differences referring | 
					
						
							|  |  |  |  |     * to implicit typing rules, so it should work with older | 
					
						
							|  |  |  |  |     * parsers as well. | 
					
						
							|  |  |  |  |     */ | 
					
						
							|  |  |  |  |   toYAML = {}@args: toJSON args; | 
					
						
							| 
									
										
										
										
											2017-06-06 22:41:22 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-26 17:26:20 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-06 22:41:22 +02:00
										 |  |  |  |   /* Pretty print a value, akin to `builtins.trace`.
 | 
					
						
							|  |  |  |  |     * Should probably be a builtin as well. | 
					
						
							|  |  |  |  |     */ | 
					
						
							|  |  |  |  |   toPretty = { | 
					
						
							|  |  |  |  |     /* If this option is true, attrsets like { __pretty = fn; val = …; }
 | 
					
						
							|  |  |  |  |        will use fn to convert val to a pretty printed representation. | 
					
						
							|  |  |  |  |        (This means fn is type Val -> String.) */ | 
					
						
							| 
									
										
										
										
											2020-09-04 17:46:12 +02:00
										 |  |  |  |     allowPrettyValues ? false, | 
					
						
							|  |  |  |  |     /* If this option is true, the output is indented with newlines for attribute sets and lists */ | 
					
						
							|  |  |  |  |     multiline ? true | 
					
						
							|  |  |  |  |   }@args: let | 
					
						
							|  |  |  |  |     go = indent: v: with builtins; | 
					
						
							| 
									
										
										
										
											2018-04-25 15:04:30 +02:00
										 |  |  |  |     let     isPath   = v: typeOf v == "path"; | 
					
						
							| 
									
										
										
										
											2020-09-04 17:46:12 +02:00
										 |  |  |  |             introSpace = if multiline then "\n${indent}  " else " "; | 
					
						
							|  |  |  |  |             outroSpace = if multiline then "\n${indent}" else " "; | 
					
						
							| 
									
										
										
										
											2018-04-25 15:04:30 +02:00
										 |  |  |  |     in if   isInt      v then toString v | 
					
						
							| 
									
										
										
										
											2018-10-14 02:55:00 +09:00
										 |  |  |  |     else if isFloat    v then "~${toString v}" | 
					
						
							| 
									
										
										
										
											2020-09-17 17:58:04 +02:00
										 |  |  |  |     else if isString   v then | 
					
						
							|  |  |  |  |       let | 
					
						
							|  |  |  |  |         # Separate a string into its lines | 
					
						
							|  |  |  |  |         newlineSplits = filter (v: ! isList v) (builtins.split "\n" v); | 
					
						
							|  |  |  |  |         # For a '' string terminated by a \n, which happens when the closing '' is on a new line | 
					
						
							|  |  |  |  |         multilineResult = "''" + introSpace + concatStringsSep introSpace (lib.init newlineSplits) + outroSpace + "''"; | 
					
						
							|  |  |  |  |         # For a '' string not terminated by a \n, which happens when the closing '' is not on a new line | 
					
						
							|  |  |  |  |         multilineResult' = "''" + introSpace + concatStringsSep introSpace newlineSplits + "''"; | 
					
						
							|  |  |  |  |         # For single lines, replace all newlines with their escaped representation | 
					
						
							|  |  |  |  |         singlelineResult = "\"" + libStr.escape [ "\"" ] (concatStringsSep "\\n" newlineSplits) + "\""; | 
					
						
							|  |  |  |  |       in if multiline && length newlineSplits > 1 then | 
					
						
							|  |  |  |  |         if lib.last newlineSplits == "" then multilineResult else multilineResult' | 
					
						
							|  |  |  |  |       else singlelineResult | 
					
						
							| 
									
										
										
										
											2018-03-26 17:26:20 +02:00
										 |  |  |  |     else if true  ==   v then "true" | 
					
						
							|  |  |  |  |     else if false ==   v then "false" | 
					
						
							| 
									
										
										
										
											2018-04-25 15:04:30 +02:00
										 |  |  |  |     else if null  ==   v then "null" | 
					
						
							|  |  |  |  |     else if isPath     v then toString v | 
					
						
							| 
									
										
										
										
											2020-09-17 18:14:18 +02:00
										 |  |  |  |     else if isList     v then | 
					
						
							|  |  |  |  |       if v == [] then "[ ]" | 
					
						
							|  |  |  |  |       else "[" + introSpace | 
					
						
							| 
									
										
										
										
											2020-09-04 17:46:12 +02:00
										 |  |  |  |         + libStr.concatMapStringsSep introSpace (go (indent + "  ")) v | 
					
						
							| 
									
										
										
										
											2020-09-17 18:14:18 +02:00
										 |  |  |  |         + outroSpace + "]" | 
					
						
							| 
									
										
										
										
											2020-09-17 18:18:50 +02:00
										 |  |  |  |     else if isFunction v then | 
					
						
							| 
									
										
										
										
											2021-02-01 16:27:38 +01:00
										 |  |  |  |       let fna = lib.functionArgs v; | 
					
						
							| 
									
										
										
										
											2020-09-17 18:18:50 +02:00
										 |  |  |  |           showFnas = concatStringsSep ", " (libAttr.mapAttrsToList | 
					
						
							|  |  |  |  |                        (name: hasDefVal: if hasDefVal then name + "?" else name) | 
					
						
							| 
									
										
										
										
											2021-02-01 16:27:38 +01:00
										 |  |  |  |                        fna); | 
					
						
							|  |  |  |  |       in if fna == {}    then "<function>" | 
					
						
							|  |  |  |  |                          else "<function, args: {${showFnas}}>" | 
					
						
							| 
									
										
										
										
											2017-06-06 22:41:22 +02:00
										 |  |  |  |     else if isAttrs    v then | 
					
						
							|  |  |  |  |       # apply pretty values if allowed | 
					
						
							|  |  |  |  |       if attrNames v == [ "__pretty" "val" ] && allowPrettyValues | 
					
						
							|  |  |  |  |          then v.__pretty v.val | 
					
						
							| 
									
										
										
										
											2020-09-17 18:14:18 +02:00
										 |  |  |  |       else if v == {} then "{ }" | 
					
						
							| 
									
										
										
										
											2018-04-25 15:04:30 +02:00
										 |  |  |  |       else if v ? type && v.type == "derivation" then | 
					
						
							| 
									
										
										
										
											2020-09-17 18:08:44 +02:00
										 |  |  |  |         "<derivation ${v.drvPath}>" | 
					
						
							| 
									
										
										
										
											2020-09-04 17:46:12 +02:00
										 |  |  |  |       else "{" + introSpace | 
					
						
							|  |  |  |  |           + libStr.concatStringsSep introSpace (libAttr.mapAttrsToList | 
					
						
							| 
									
										
										
										
											2017-06-06 22:41:22 +02:00
										 |  |  |  |               (name: value: | 
					
						
							| 
									
										
										
										
											2020-09-04 17:46:12 +02:00
										 |  |  |  |                 "${libStr.escapeNixIdentifier name} = ${go (indent + "  ") value};") v) | 
					
						
							|  |  |  |  |         + outroSpace + "}" | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |     else abort "generators.toPretty: should never happen (v = ${v})"; | 
					
						
							| 
									
										
										
										
											2020-09-04 17:46:12 +02:00
										 |  |  |  |   in go ""; | 
					
						
							| 
									
										
										
										
											2017-06-06 22:41:22 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-27 15:35:07 -04:00
										 |  |  |  |   # PLIST handling | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |   toPlist = {}: v: let | 
					
						
							| 
									
										
										
										
											2018-07-03 12:24:54 -04:00
										 |  |  |  |     isFloat = builtins.isFloat or (x: false); | 
					
						
							|  |  |  |  |     expr = ind: x:  with builtins; | 
					
						
							| 
									
										
										
										
											2019-04-24 05:48:22 +02:00
										 |  |  |  |       if x == null  then "" else | 
					
						
							| 
									
										
										
										
											2018-07-03 12:24:54 -04:00
										 |  |  |  |       if isBool x   then bool ind x else | 
					
						
							|  |  |  |  |       if isInt x    then int ind x else | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |       if isString x then str ind x else | 
					
						
							| 
									
										
										
										
											2018-07-03 12:24:54 -04:00
										 |  |  |  |       if isList x   then list ind x else | 
					
						
							|  |  |  |  |       if isAttrs x  then attrs ind x else | 
					
						
							|  |  |  |  |       if isFloat x  then float ind x else | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |       abort "generators.toPlist: should never happen (v = ${v})"; | 
					
						
							| 
									
										
										
										
											2018-06-28 11:11:19 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |     literal = ind: x: ind + x; | 
					
						
							| 
									
										
										
										
											2018-06-28 11:11:19 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |     bool = ind: x: literal ind  (if x then "<true/>" else "<false/>"); | 
					
						
							|  |  |  |  |     int = ind: x: literal ind "<integer>${toString x}</integer>"; | 
					
						
							|  |  |  |  |     str = ind: x: literal ind "<string>${x}</string>"; | 
					
						
							|  |  |  |  |     key = ind: x: literal ind "<key>${x}</key>"; | 
					
						
							| 
									
										
										
										
											2018-07-03 12:24:54 -04:00
										 |  |  |  |     float = ind: x: literal ind "<real>${toString x}</real>"; | 
					
						
							| 
									
										
										
										
											2018-06-28 11:11:19 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |     indent = ind: expr "\t${ind}"; | 
					
						
							| 
									
										
										
										
											2018-06-28 11:11:19 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |     item = ind: libStr.concatMapStringsSep "\n" (indent ind); | 
					
						
							| 
									
										
										
										
											2018-06-28 11:11:19 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |     list = ind: x: libStr.concatStringsSep "\n" [ | 
					
						
							|  |  |  |  |       (literal ind "<array>") | 
					
						
							|  |  |  |  |       (item ind x) | 
					
						
							|  |  |  |  |       (literal ind "</array>") | 
					
						
							| 
									
										
										
										
											2018-06-28 11:11:19 -04:00
										 |  |  |  |     ]; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |     attrs = ind: x: libStr.concatStringsSep "\n" [ | 
					
						
							|  |  |  |  |       (literal ind "<dict>") | 
					
						
							|  |  |  |  |       (attr ind x) | 
					
						
							|  |  |  |  |       (literal ind "</dict>") | 
					
						
							| 
									
										
										
										
											2018-06-28 11:11:19 -04:00
										 |  |  |  |     ]; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |     attr = let attrFilter = name: value: name != "_module" && value != null; | 
					
						
							| 
									
										
										
										
											2018-06-28 11:11:19 -04:00
										 |  |  |  |     in ind: x: libStr.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList | 
					
						
							|  |  |  |  |       (name: value: lib.optional (attrFilter name value) [ | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |       (key "\t${ind}" name) | 
					
						
							|  |  |  |  |       (expr "\t${ind}" value) | 
					
						
							| 
									
										
										
										
											2018-06-28 11:11:19 -04:00
										 |  |  |  |     ]) x)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-28 11:12:39 -04:00
										 |  |  |  |   in ''<?xml version="1.0" encoding="UTF-8"?>
 | 
					
						
							|  |  |  |  | <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | 
					
						
							|  |  |  |  | <plist version="1.0"> | 
					
						
							|  |  |  |  | ${expr "" v} | 
					
						
							|  |  |  |  | </plist>'';
 | 
					
						
							| 
									
										
										
										
											2018-06-27 15:35:07 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-24 11:20:36 +01:00
										 |  |  |  |   /* Translate a simple Nix expression to Dhall notation.
 | 
					
						
							|  |  |  |  |    * Note that integers are translated to Integer and never | 
					
						
							|  |  |  |  |    * the Natural type. | 
					
						
							|  |  |  |  |   */ | 
					
						
							|  |  |  |  |   toDhall = { }@args: v: | 
					
						
							|  |  |  |  |     with builtins; | 
					
						
							|  |  |  |  |     let concatItems = lib.strings.concatStringsSep ", "; | 
					
						
							|  |  |  |  |     in if isAttrs v then | 
					
						
							|  |  |  |  |       "{ ${ | 
					
						
							|  |  |  |  |         concatItems (lib.attrsets.mapAttrsToList | 
					
						
							|  |  |  |  |           (key: value: "${key} = ${toDhall args value}") v) | 
					
						
							|  |  |  |  |       } }"
 | 
					
						
							|  |  |  |  |     else if isList v then | 
					
						
							|  |  |  |  |       "[ ${concatItems (map (toDhall args) v)} ]" | 
					
						
							|  |  |  |  |     else if isInt v then | 
					
						
							|  |  |  |  |       "${if v < 0 then "" else "+"}${toString v}" | 
					
						
							|  |  |  |  |     else if isBool v then | 
					
						
							|  |  |  |  |       (if v then "True" else "False") | 
					
						
							|  |  |  |  |     else if isFunction v then | 
					
						
							|  |  |  |  |       abort "generators.toDhall: cannot convert a function to Dhall" | 
					
						
							|  |  |  |  |     else if isNull v then | 
					
						
							|  |  |  |  |       abort "generators.toDhall: cannot convert a null to Dhall" | 
					
						
							|  |  |  |  |     else | 
					
						
							|  |  |  |  |       builtins.toJSON v; | 
					
						
							| 
									
										
										
										
											2016-11-06 01:51:13 +01:00
										 |  |  |  | } |