at 15.09-beta 4.9 kB view raw
1let lib = import ./default.nix; 2 3inherit (builtins) trace attrNamesToStr isAttrs isFunction isList isInt 4 isString isBool head substring attrNames; 5 6inherit (lib) all id mapAttrsFlatten elem; 7 8in 9 10rec { 11 12 inherit (builtins) addErrorContext; 13 14 addErrorContextToAttrs = lib.mapAttrs (a: v: lib.addErrorContext "while evaluating ${a}" v); 15 16 traceIf = p: msg: x: if p then trace msg x else x; 17 18 traceVal = x: trace x x; 19 traceXMLVal = x: trace (builtins.toXML x) x; 20 traceXMLValMarked = str: x: trace (str + builtins.toXML x) x; 21 22 # this can help debug your code as well - designed to not produce thousands of lines 23 traceShowVal = x : trace (showVal x) x; 24 traceShowValMarked = str: x: trace (str + showVal x) x; 25 attrNamesToStr = a : lib.concatStringsSep "; " (map (x : "${x}=") (attrNames a)); 26 showVal = x : 27 if isAttrs x then 28 if x ? outPath then "x is a derivation, name ${if x ? name then x.name else "<no name>"}, { ${attrNamesToStr x} }" 29 else "x is attr set { ${attrNamesToStr x} }" 30 else if isFunction x then "x is a function" 31 else if x == [] then "x is an empty list" 32 else if isList x then "x is a list, first element is: ${showVal (head x)}" 33 else if x == true then "x is boolean true" 34 else if x == false then "x is boolean false" 35 else if x == null then "x is null" 36 else if isInt x then "x is an integer `${toString x}'" 37 else if isString x then "x is a string `${substring 0 50 x}...'" 38 else "x is probably a path `${substring 0 50 (toString x)}...'"; 39 40 # trace the arguments passed to function and its result 41 # maybe rewrite these functions in a traceCallXml like style. Then one function is enough 42 traceCall = n : f : a : let t = n2 : x : traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a)); 43 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)); 44 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)); 45 46 # FIXME: rename this? 47 traceValIfNot = c: x: 48 if c x then true else trace (showVal x) false; 49 50 /* Evaluate a set of tests. A test is an attribute set {expr, 51 expected}, denoting an expression and its expected result. The 52 result is a list of failed tests, each represented as {name, 53 expected, actual}, denoting the attribute name of the failing 54 test and its expected and actual results. Used for regression 55 testing of the functions in lib; see tests.nix for an example. 56 Only tests having names starting with "test" are run. 57 Add attr { tests = ["testName"]; } to run these test only 58 */ 59 runTests = tests: lib.concatLists (lib.attrValues (lib.mapAttrs (name: test: 60 let testsToRun = if tests ? tests then tests.tests else []; 61 in if (substring 0 4 name == "test" || elem name testsToRun) 62 && ((testsToRun == []) || elem name tests.tests) 63 && (test.expr != test.expected) 64 65 then [ { inherit name; expected = test.expected; result = test.expr; } ] 66 else [] ) tests)); 67 68 # create a test assuming that list elements are true 69 # usage: { testX = allTrue [ true ]; } 70 testAllTrue = expr : { inherit expr; expected = map (x: true) expr; }; 71 72 # evaluate everything once so that errors will occur earlier 73 # hacky: traverse attrs by adding a dummy 74 # ignores functions (should this behavior change?) See strictf 75 # 76 # Note: This should be a primop! Something like seq of haskell would be nice to 77 # have as well. It's used fore debugging only anyway 78 strict = x : 79 let 80 traverse = x : 81 if isString x then true 82 else if isAttrs x then 83 if x ? outPath then true 84 else all id (mapAttrsFlatten (n: traverse) x) 85 else if isList x then 86 all id (map traverse x) 87 else if isBool x then true 88 else if isFunction x then true 89 else if isInt x then true 90 else if x == null then true 91 else true; # a (store) path? 92 in if traverse x then x else throw "else never reached"; 93 94 # example: (traceCallXml "myfun" id 3) will output something like 95 # calling myfun arg 1: 3 result: 3 96 # this forces deep evaluation of all arguments and the result! 97 # note: if result doesn't evaluate you'll get no trace at all (FIXME) 98 # args should be printed in any case 99 traceCallXml = a: 100 if !isInt a then 101 traceCallXml 1 "calling ${a}\n" 102 else 103 let nr = a; 104 in (str: expr: 105 if isFunction expr then 106 (arg: 107 traceCallXml (builtins.add 1 nr) "${str}\n arg ${builtins.toString nr} is \n ${builtins.toXML (strict arg)}" (expr arg) 108 ) 109 else 110 let r = strict expr; 111 in trace "${str}\n result:\n${builtins.toXML r}" r 112 ); 113}