| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  | /* Collection of functions useful for debugging
 | 
					
						
							|  |  |  |    broken nix expressions. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    * `trace`-like functions take two values, print | 
					
						
							|  |  |  |      the first to stderr and return the second. | 
					
						
							|  |  |  |    * `traceVal`-like functions take one argument | 
					
						
							|  |  |  |      which both printed and returned. | 
					
						
							|  |  |  |    * `traceSeq`-like functions fully evaluate their | 
					
						
							|  |  |  |      traced value before printing (not just to “weak | 
					
						
							|  |  |  |      head normal form” like trace does by default). | 
					
						
							|  |  |  |    * Functions that end in `-Fn` take an additional | 
					
						
							|  |  |  |      function as their first argument, which is applied | 
					
						
							|  |  |  |      to the traced value before it is printed. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2017-07-28 20:05:35 -04:00
										 |  |  | { lib }: | 
					
						
							|  |  |  | let | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  |   inherit (builtins) trace isAttrs isList isInt | 
					
						
							|  |  |  |           head substring attrNames; | 
					
						
							|  |  |  |   inherit (lib) id elem isFunction; | 
					
						
							|  |  |  | in | 
					
						
							| 
									
										
										
										
											2009-05-24 10:57:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  | rec { | 
					
						
							| 
									
										
										
										
											2009-11-22 21:28:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  |   # -- TRACING -- | 
					
						
							| 
									
										
										
										
											2009-05-24 10:57:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 20:51:26 +01:00
										 |  |  |   /* Conditionally trace the supplied message, based on a predicate.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: traceIf :: bool -> string -> a -> a | 
					
						
							| 
									
										
										
										
											2009-03-06 23:21:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        traceIf true "hello" 3 | 
					
						
							|  |  |  |        trace: hello | 
					
						
							|  |  |  |        => 3 | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-28 20:51:26 +01:00
										 |  |  |   traceIf = | 
					
						
							|  |  |  |     # Predicate to check | 
					
						
							|  |  |  |     pred: | 
					
						
							|  |  |  |     # Message that should be traced | 
					
						
							|  |  |  |     msg: | 
					
						
							|  |  |  |     # Value to return | 
					
						
							|  |  |  |     x: if pred then trace msg x else x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Trace the supplied value after applying a function to it, and
 | 
					
						
							|  |  |  |      return the original value. | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 20:51:26 +01:00
										 |  |  |      Type: traceValFn :: (a -> b) -> a -> a | 
					
						
							| 
									
										
										
										
											2014-10-04 17:53:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        traceValFn (v: "mystring ${v}") "foo" | 
					
						
							|  |  |  |        trace: mystring foo | 
					
						
							|  |  |  |        => "foo" | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-28 20:51:26 +01:00
										 |  |  |   traceValFn = | 
					
						
							|  |  |  |     # Function to apply | 
					
						
							|  |  |  |     f: | 
					
						
							|  |  |  |     # Value to trace and return | 
					
						
							|  |  |  |     x: trace (f x) x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Trace the supplied value and return it.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Type: traceVal :: a -> a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Example: | 
					
						
							|  |  |  |        traceVal 42 | 
					
						
							|  |  |  |        # trace: 42 | 
					
						
							|  |  |  |        => 42 | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-04-02 17:21:35 +02:00
										 |  |  |   traceVal = traceValFn id; | 
					
						
							| 
									
										
										
										
											2017-06-06 22:42:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  |   /* `builtins.trace`, but the value is `builtins.deepSeq`ed first.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 20:51:26 +01:00
										 |  |  |      Type: traceSeq :: a -> b -> b | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  |      Example: | 
					
						
							|  |  |  |        trace { a.b.c = 3; } null | 
					
						
							|  |  |  |        trace: { a = <CODE>; } | 
					
						
							|  |  |  |        => null | 
					
						
							|  |  |  |        traceSeq { a.b.c = 3; } null | 
					
						
							|  |  |  |        trace: { a = { b = { c = 3; }; }; } | 
					
						
							|  |  |  |        => null | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-28 20:51:26 +01:00
										 |  |  |   traceSeq = | 
					
						
							|  |  |  |     # The value to trace | 
					
						
							|  |  |  |     x: | 
					
						
							|  |  |  |     # The value to return | 
					
						
							|  |  |  |     y: trace (builtins.deepSeq x x) y; | 
					
						
							| 
									
										
										
										
											2017-06-06 22:42:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  |   /* Like `traceSeq`, but only evaluate down to depth n.
 | 
					
						
							|  |  |  |      This is very useful because lots of `traceSeq` usages | 
					
						
							|  |  |  |      lead to an infinite recursion. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Example: | 
					
						
							|  |  |  |        traceSeqN 2 { a.b.c = 3; } null | 
					
						
							|  |  |  |        trace: { a = { b = {…}; }; } | 
					
						
							|  |  |  |        => null | 
					
						
							| 
									
										
										
										
											2017-06-06 22:42:30 +02:00
										 |  |  |    */ | 
					
						
							|  |  |  |   traceSeqN = depth: x: y: with lib; | 
					
						
							|  |  |  |     let snip = v: if      isList  v then noQuotes "[…]" v | 
					
						
							|  |  |  |                   else if isAttrs v then noQuotes "{…}" v | 
					
						
							|  |  |  |                   else v; | 
					
						
							|  |  |  |         noQuotes = str: v: { __pretty = const str; val = v; }; | 
					
						
							|  |  |  |         modify = n: fn: v: if (n == 0) then fn v | 
					
						
							|  |  |  |                       else if isList  v then map (modify (n - 1) fn) v | 
					
						
							|  |  |  |                       else if isAttrs v then mapAttrs | 
					
						
							|  |  |  |                         (const (modify (n - 1) fn)) v | 
					
						
							|  |  |  |                       else v; | 
					
						
							|  |  |  |     in trace (generators.toPretty { allowPrettyValues = true; } | 
					
						
							|  |  |  |                (modify depth snip x)) y; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 20:51:26 +01:00
										 |  |  |   /* A combination of `traceVal` and `traceSeq` that applies a
 | 
					
						
							|  |  |  |      provided function to the value to be traced after `deepSeq`ing | 
					
						
							|  |  |  |      it. | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  |   traceValSeqFn = | 
					
						
							|  |  |  |     # Function to apply | 
					
						
							|  |  |  |     f: | 
					
						
							|  |  |  |     # Value to trace | 
					
						
							|  |  |  |     v: traceValFn f (builtins.deepSeq v v); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* A combination of `traceVal` and `traceSeq`. */ | 
					
						
							| 
									
										
										
										
											2018-04-02 17:21:35 +02:00
										 |  |  |   traceValSeq = traceValSeqFn id; | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 20:51:26 +01:00
										 |  |  |   /* A combination of `traceVal` and `traceSeqN` that applies a
 | 
					
						
							|  |  |  |   provided function to the value to be traced. */ | 
					
						
							|  |  |  |   traceValSeqNFn = | 
					
						
							|  |  |  |     # Function to apply | 
					
						
							|  |  |  |     f: | 
					
						
							|  |  |  |     depth: | 
					
						
							|  |  |  |     # Value to trace | 
					
						
							|  |  |  |     v: traceSeqN depth (f v) v; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  |   /* A combination of `traceVal` and `traceSeqN`. */ | 
					
						
							| 
									
										
										
										
											2018-04-02 17:21:35 +02:00
										 |  |  |   traceValSeqN = traceValSeqNFn id; | 
					
						
							| 
									
										
										
										
											2017-06-06 22:42:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-26 01:28:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  |   # -- TESTING -- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 20:51:26 +01:00
										 |  |  |   /* Evaluate a set of tests.  A test is an attribute set `{expr,
 | 
					
						
							|  |  |  |      expected}`, denoting an expression and its expected result.  The | 
					
						
							|  |  |  |      result is a list of failed tests, each represented as `{name, | 
					
						
							|  |  |  |      expected, actual}`, denoting the attribute name of the failing | 
					
						
							|  |  |  |      test and its expected and actual results. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Used for regression testing of the functions in lib; see | 
					
						
							|  |  |  |      tests.nix for an example. Only tests having names starting with | 
					
						
							|  |  |  |      "test" are run. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Add attr { tests = ["testName"]; } to run these tests only. | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-10-28 20:51:26 +01:00
										 |  |  |   runTests = | 
					
						
							|  |  |  |     # Tests to run | 
					
						
							|  |  |  |     tests: lib.concatLists (lib.attrValues (lib.mapAttrs (name: test: | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  |     let testsToRun = if tests ? tests then tests.tests else []; | 
					
						
							|  |  |  |     in if (substring 0 4 name == "test" ||  elem name testsToRun) | 
					
						
							|  |  |  |        && ((testsToRun == []) || elem name tests.tests) | 
					
						
							|  |  |  |        && (test.expr != test.expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       then [ { inherit name; expected = test.expected; result = test.expr; } ] | 
					
						
							|  |  |  |       else [] ) tests)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 20:51:26 +01:00
										 |  |  |   /* Create a test assuming that list elements are `true`.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      Example: | 
					
						
							|  |  |  |        { testX = allTrue [ true ]; } | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2018-04-03 08:48:04 +02:00
										 |  |  |   testAllTrue = expr: { inherit expr; expected = map (x: true) expr; }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # -- DEPRECATED -- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-11 17:39:40 -05:00
										 |  |  |   traceShowVal = x: trace (showVal x) x; | 
					
						
							| 
									
										
										
										
											2009-05-24 10:57:46 +00:00
										 |  |  |   traceShowValMarked = str: x: trace (str + showVal x) x; | 
					
						
							| 
									
										
										
										
											2018-04-02 19:13:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   attrNamesToStr = a: | 
					
						
							|  |  |  |     trace ( "Warning: `attrNamesToStr` is deprecated " | 
					
						
							| 
									
										
										
										
											2018-04-03 14:04:05 +02:00
										 |  |  |           + "and will be removed in the next release. " | 
					
						
							|  |  |  |           + "Please use more specific concatenation " | 
					
						
							|  |  |  |           + "for your uses (`lib.concat(Map)StringsSep`)." ) | 
					
						
							| 
									
										
										
										
											2018-04-02 19:13:51 +02:00
										 |  |  |     (lib.concatStringsSep "; " (map (x: "${x}=") (attrNames a))); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-02 18:30:21 +02:00
										 |  |  |   showVal = with lib; | 
					
						
							|  |  |  |     trace ( "Warning: `showVal` is deprecated " | 
					
						
							|  |  |  |           + "and will be removed in the next release, " | 
					
						
							|  |  |  |           + "please use `traceSeqN`" ) | 
					
						
							|  |  |  |     (let | 
					
						
							|  |  |  |       modify = v: | 
					
						
							|  |  |  |         let pr = f: { __pretty = f; val = v; }; | 
					
						
							|  |  |  |         in   if isDerivation v then pr | 
					
						
							|  |  |  |           (drv: "<δ:${drv.name}:${concatStringsSep "," | 
					
						
							|  |  |  |                                  (attrNames drv)}>")
 | 
					
						
							|  |  |  |         else if [] ==   v then pr (const "[]") | 
					
						
							|  |  |  |         else if isList  v then pr (l: "[ ${go (head l)}, … ]") | 
					
						
							|  |  |  |         else if isAttrs v then pr | 
					
						
							|  |  |  |           (a: "{ ${ concatStringsSep ", " (attrNames a)} }") | 
					
						
							|  |  |  |         else v; | 
					
						
							|  |  |  |       go = x: generators.toPretty | 
					
						
							|  |  |  |         { allowPrettyValues = true; } | 
					
						
							|  |  |  |         (modify x); | 
					
						
							|  |  |  |     in go); | 
					
						
							| 
									
										
										
										
											2009-11-14 20:14:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-02 19:13:51 +02:00
										 |  |  |   traceXMLVal = x: | 
					
						
							|  |  |  |     trace ( "Warning: `traceXMLVal` is deprecated " | 
					
						
							| 
									
										
										
										
											2018-04-03 14:04:05 +02:00
										 |  |  |           + "and will be removed in the next release. " | 
					
						
							|  |  |  |           + "Please use `traceValFn builtins.toXML`." ) | 
					
						
							| 
									
										
										
										
											2018-04-02 19:13:51 +02:00
										 |  |  |     (trace (builtins.toXML x) x); | 
					
						
							|  |  |  |   traceXMLValMarked = str: x: | 
					
						
							|  |  |  |     trace ( "Warning: `traceXMLValMarked` is deprecated " | 
					
						
							| 
									
										
										
										
											2018-04-03 14:04:05 +02:00
										 |  |  |           + "and will be removed in the next release. " | 
					
						
							|  |  |  |           + "Please use `traceValFn (x: str + builtins.toXML x)`." ) | 
					
						
							| 
									
										
										
										
											2018-04-02 19:13:51 +02:00
										 |  |  |     (trace (str + builtins.toXML x) x); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-04 17:53:56 +02:00
										 |  |  |   # trace the arguments passed to function and its result | 
					
						
							| 
									
										
										
										
											2009-11-22 21:28:36 +00:00
										 |  |  |   # maybe rewrite these functions in a traceCallXml like style. Then one function is enough | 
					
						
							| 
									
										
										
										
											2017-03-11 17:39:40 -05:00
										 |  |  |   traceCall  = n: f: a: let t = n2: x: traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a)); | 
					
						
							|  |  |  |   traceCall2 = n: f: a: b: let t = n2: x: traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a) (t "arg 2" b)); | 
					
						
							|  |  |  |   traceCall3 = n: f: a: b: c: let t = n2: x: traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a) (t "arg 2" b) (t "arg 3" c)); | 
					
						
							| 
									
										
										
										
											2009-03-06 23:21:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-26 12:42:00 +00:00
										 |  |  |   traceValIfNot = c: x: | 
					
						
							| 
									
										
										
										
											2018-04-02 20:41:59 +02:00
										 |  |  |     trace ( "Warning: `traceValIfNot` is deprecated " | 
					
						
							| 
									
										
										
										
											2018-04-03 14:04:05 +02:00
										 |  |  |           + "and will be removed in the next release. " | 
					
						
							|  |  |  |           + "Please use `if/then/else` and `traceValSeq 1`.") | 
					
						
							| 
									
										
										
										
											2018-04-02 20:41:59 +02:00
										 |  |  |     (if c x then true else traceSeq (showVal x) false); | 
					
						
							| 
									
										
										
										
											2009-03-31 13:03:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-02 21:00:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   addErrorContextToAttrs = attrs: | 
					
						
							|  |  |  |     trace ( "Warning: `addErrorContextToAttrs` is deprecated " | 
					
						
							| 
									
										
										
										
											2018-04-03 14:04:05 +02:00
										 |  |  |           + "and will be removed in the next release. " | 
					
						
							|  |  |  |           + "Please use `builtins.addErrorContext` directly." ) | 
					
						
							| 
									
										
										
										
											2018-04-02 21:00:47 +02:00
										 |  |  |     (lib.mapAttrs (a: v: lib.addErrorContext "while evaluating ${a}" v) attrs); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-22 21:28:36 +00:00
										 |  |  |   # example: (traceCallXml "myfun" id 3) will output something like | 
					
						
							|  |  |  |   # calling myfun arg 1: 3 result: 3 | 
					
						
							|  |  |  |   # this forces deep evaluation of all arguments and the result! | 
					
						
							|  |  |  |   # note: if result doesn't evaluate you'll get no trace at all (FIXME) | 
					
						
							|  |  |  |   #       args should be printed in any case | 
					
						
							|  |  |  |   traceCallXml = a: | 
					
						
							| 
									
										
										
										
											2018-04-03 08:00:02 +02:00
										 |  |  |     trace ( "Warning: `traceCallXml` is deprecated " | 
					
						
							| 
									
										
										
										
											2018-04-03 14:04:05 +02:00
										 |  |  |           + "and will be removed in the next release. " | 
					
						
							|  |  |  |           + "Please complain if you use the function regularly." ) | 
					
						
							| 
									
										
										
										
											2018-04-03 08:00:02 +02:00
										 |  |  |     (if !isInt a then | 
					
						
							| 
									
										
										
										
											2009-11-22 21:28:36 +00:00
										 |  |  |       traceCallXml 1 "calling ${a}\n" | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       let nr = a; | 
					
						
							|  |  |  |       in (str: expr: | 
					
						
							|  |  |  |           if isFunction expr then | 
					
						
							| 
									
										
										
										
											2014-10-04 17:53:56 +02:00
										 |  |  |             (arg: | 
					
						
							| 
									
										
										
										
											2018-04-02 17:25:03 +02:00
										 |  |  |               traceCallXml (builtins.add 1 nr) "${str}\n arg ${builtins.toString nr} is \n ${builtins.toXML (builtins.seq arg arg)}" (expr arg) | 
					
						
							| 
									
										
										
										
											2009-11-22 21:28:36 +00:00
										 |  |  |             ) | 
					
						
							| 
									
										
										
										
											2014-10-04 17:53:56 +02:00
										 |  |  |           else | 
					
						
							| 
									
										
										
										
											2018-04-02 17:25:03 +02:00
										 |  |  |             let r = builtins.seq expr expr; | 
					
						
							| 
									
										
										
										
											2015-03-19 15:48:54 +00:00
										 |  |  |             in trace "${str}\n result:\n${builtins.toXML r}" r | 
					
						
							| 
									
										
										
										
											2018-04-03 08:00:02 +02:00
										 |  |  |       )); | 
					
						
							| 
									
										
										
										
											2009-03-06 23:21:35 +00:00
										 |  |  | } |