diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/debug.nix | 184 | ||||
-rw-r--r-- | lib/default.nix | 11 | ||||
-rw-r--r-- | lib/modules.nix | 4 | ||||
-rw-r--r-- | lib/trivial.nix | 11 |
4 files changed, 143 insertions, 67 deletions
diff --git a/lib/debug.nix b/lib/debug.nix index d163e60b695..91a9265a6b5 100644 --- a/lib/debug.nix +++ b/lib/debug.nix @@ -1,34 +1,67 @@ +/* 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. +*/ { lib }: - let - -inherit (builtins) trace attrNamesToStr isAttrs isList isInt - isString isBool head substring attrNames; - -inherit (lib) all id mapAttrsFlatten elem isFunction; - + inherit (builtins) trace isAttrs isList isInt + head substring attrNames; + inherit (lib) id elem isFunction; in rec { - inherit (builtins) addErrorContext; - - addErrorContextToAttrs = lib.mapAttrs (a: v: lib.addErrorContext "while evaluating ${a}" v); + # -- TRACING -- - traceIf = p: msg: x: if p then trace msg x else x; + /* Trace msg, but only if pred is true. - traceVal = x: trace x x; - traceXMLVal = x: trace (builtins.toXML x) x; - traceXMLValMarked = str: x: trace (str + builtins.toXML x) x; + Example: + traceIf true "hello" 3 + trace: hello + => 3 + */ + traceIf = pred: msg: x: if pred then trace msg x else x; - # strict trace functions (traced structure is fully evaluated and printed) + /* Trace the value and also return it. - /* `builtins.trace`, but the value is `builtins.deepSeq`ed first. */ + Example: + traceValFn (v: "mystring ${v}") "foo" + trace: mystring foo + => "foo" + */ + traceValFn = f: x: trace (f x) x; + traceVal = traceValFn id; + + /* `builtins.trace`, but the value is `builtins.deepSeq`ed first. + + Example: + trace { a.b.c = 3; } null + trace: { a = <CODE>; } + => null + traceSeq { a.b.c = 3; } null + trace: { a = { b = { c = 3; }; }; } + => null + */ traceSeq = x: y: trace (builtins.deepSeq x x) y; - /* Like `traceSeq`, but only down to depth n. - * This is very useful because lots of `traceSeq` usages - * lead to an infinite recursion. + /* 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 */ traceSeqN = depth: x: y: with lib; let snip = v: if isList v then noQuotes "[…]" v @@ -43,39 +76,16 @@ rec { in trace (generators.toPretty { allowPrettyValues = true; } (modify depth snip x)) y; - /* `traceSeq`, but the same value is traced and returned */ - traceValSeq = v: traceVal (builtins.deepSeq v v); - /* `traceValSeq` but with fixed depth */ - traceValSeqN = depth: v: traceSeqN depth v v; + /* A combination of `traceVal` and `traceSeq` */ + traceValSeqFn = f: v: traceVal f (builtins.deepSeq v v); + traceValSeq = traceValSeqFn id; + /* A combination of `traceVal` and `traceSeqN`. */ + traceValSeqNFn = f: depth: v: traceSeqN depth (f v) v; + traceValSeqN = traceValSeqNFn id; - # this can help debug your code as well - designed to not produce thousands of lines - traceShowVal = x: trace (showVal x) x; - traceShowValMarked = str: x: trace (str + showVal x) x; - attrNamesToStr = a: lib.concatStringsSep "; " (map (x: "${x}=") (attrNames a)); - showVal = x: - if isAttrs x then - if x ? outPath then "x is a derivation, name ${if x ? name then x.name else "<no name>"}, { ${attrNamesToStr x} }" - else "x is attr set { ${attrNamesToStr x} }" - else if isFunction x then "x is a function" - else if x == [] then "x is an empty list" - else if isList x then "x is a list, first element is: ${showVal (head x)}" - else if x == true then "x is boolean true" - else if x == false then "x is boolean false" - else if x == null then "x is null" - else if isInt x then "x is an integer `${toString x}'" - else if isString x then "x is a string `${substring 0 50 x}...'" - else "x is probably a path `${substring 0 50 (toString x)}...'"; - # trace the arguments passed to function and its result - # maybe rewrite these functions in a traceCallXml like style. Then one function is enough - 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)); - - # FIXME: rename this? - traceValIfNot = c: x: - if c x then true else trace (showVal x) false; + # -- TESTING -- /* Evaluate a set of tests. A test is an attribute set {expr, expected}, denoting an expression and its expected result. The @@ -99,9 +109,68 @@ rec { # usage: { testX = allTrue [ true ]; } testAllTrue = expr: { inherit expr; expected = map (x: true) expr; }; - strict = v: - trace "Warning: strict is deprecated and will be removed in the next release" - (builtins.seq v v); + + # -- DEPRECATED -- + + traceShowVal = x: trace (showVal x) x; + traceShowValMarked = str: x: trace (str + showVal x) x; + + attrNamesToStr = a: + trace ( "Warning: `attrNamesToStr` is deprecated " + + "and will be removed in the next release. " + + "Please use more specific concatenation " + + "for your uses (`lib.concat(Map)StringsSep`)." ) + (lib.concatStringsSep "; " (map (x: "${x}=") (attrNames a))); + + 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); + + traceXMLVal = x: + trace ( "Warning: `traceXMLVal` is deprecated " + + "and will be removed in the next release. " + + "Please use `traceValFn builtins.toXML`." ) + (trace (builtins.toXML x) x); + traceXMLValMarked = str: x: + trace ( "Warning: `traceXMLValMarked` is deprecated " + + "and will be removed in the next release. " + + "Please use `traceValFn (x: str + builtins.toXML x)`." ) + (trace (str + builtins.toXML x) x); + + # trace the arguments passed to function and its result + # maybe rewrite these functions in a traceCallXml like style. Then one function is enough + 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)); + + traceValIfNot = c: x: + trace ( "Warning: `traceValIfNot` is deprecated " + + "and will be removed in the next release. " + + "Please use `if/then/else` and `traceValSeq 1`.") + (if c x then true else traceSeq (showVal x) false); + + + addErrorContextToAttrs = attrs: + trace ( "Warning: `addErrorContextToAttrs` is deprecated " + + "and will be removed in the next release. " + + "Please use `builtins.addErrorContext` directly." ) + (lib.mapAttrs (a: v: lib.addErrorContext "while evaluating ${a}" v) attrs); # example: (traceCallXml "myfun" id 3) will output something like # calling myfun arg 1: 3 result: 3 @@ -109,17 +178,20 @@ rec { # note: if result doesn't evaluate you'll get no trace at all (FIXME) # args should be printed in any case traceCallXml = a: - if !isInt a then + trace ( "Warning: `traceCallXml` is deprecated " + + "and will be removed in the next release. " + + "Please complain if you use the function regularly." ) + (if !isInt a then traceCallXml 1 "calling ${a}\n" else let nr = a; in (str: expr: if isFunction expr then (arg: - traceCallXml (builtins.add 1 nr) "${str}\n arg ${builtins.toString nr} is \n ${builtins.toXML (strict arg)}" (expr arg) + traceCallXml (builtins.add 1 nr) "${str}\n arg ${builtins.toString nr} is \n ${builtins.toXML (builtins.seq arg arg)}" (expr arg) ) else - let r = strict expr; + let r = builtins.seq expr expr; in trace "${str}\n result:\n${builtins.toXML r}" r - ); + )); } diff --git a/lib/default.nix b/lib/default.nix index c292ed33e1d..60ce01a93cd 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -58,7 +58,7 @@ let replaceStrings seq stringLength sub substring tail; inherit (trivial) id const concat or and boolToString mergeAttrs flip mapNullable inNixShell min max importJSON warn info - nixpkgsVersion mod compare splitByAndCompare + nixpkgsVersion version mod compare splitByAndCompare functionArgs setFunctionArgs isFunction; inherit (fixedPoints) fix fix' extends composeExtensions @@ -115,11 +115,12 @@ let unknownModule mkOption; inherit (types) isType setType defaultTypeMerge defaultFunctor isOptionType mkOptionType; - inherit (debug) addErrorContextToAttrs traceIf traceVal + inherit (debug) addErrorContextToAttrs traceIf traceVal traceValFn traceXMLVal traceXMLValMarked traceSeq traceSeqN traceValSeq - traceValSeqN traceShowVal traceShowValMarked - showVal traceCall traceCall2 traceCall3 traceValIfNot runTests - testAllTrue strict traceCallXml attrNamesToStr; + traceValSeqFn traceValSeqN traceValSeqNFn traceShowVal + traceShowValMarked showVal traceCall traceCall2 traceCall3 + traceValIfNot runTests testAllTrue traceCallXml + attrNamesToStr; inherit (misc) maybeEnv defaultMergeArg defaultMerge foldArgs defaultOverridableDelayableArgs composedArgsAndFun maybeAttrNullable maybeAttr ifEnable checkFlag getValue diff --git a/lib/modules.nix b/lib/modules.nix index 4ef982c7ec9..6c8033322a5 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -159,7 +159,7 @@ rec { context = name: ''while evaluating the module argument `${name}' in "${key}":''; extraArgs = builtins.listToAttrs (map (name: { inherit name; - value = addErrorContext (context name) + value = builtins.addErrorContext (context name) (args.${name} or config._module.args.${name}); }) requiredArgs); @@ -309,7 +309,7 @@ rec { res.mergedValue; in opt // - { value = addErrorContext "while evaluating the option `${showOption loc}':" value; + { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value; definitions = map (def: def.value) res.defsFinal; files = map (def: def.file) res.defsFinal; inherit (res) isDefined; diff --git a/lib/trivial.nix b/lib/trivial.nix index a928e1dbca9..251cb796db0 100644 --- a/lib/trivial.nix +++ b/lib/trivial.nix @@ -58,11 +58,14 @@ rec { inherit (lib.strings) fileContents; + release = fileContents ../.version; + versionSuffix = let suffixFile = ../.version-suffix; in + if pathExists suffixFile then fileContents suffixFile else "pre-git"; + # Return the Nixpkgs version number. - nixpkgsVersion = - let suffixFile = ../.version-suffix; in - fileContents ../.version - + (if pathExists suffixFile then fileContents suffixFile else "pre-git"); + version = release + versionSuffix; + + nixpkgsVersion = builtins.trace "`lib.nixpkgsVersion` is deprecated, use `lib.version` instead!" version; # Whether we're being called by nix-shell. inNixShell = builtins.getEnv "IN_NIX_SHELL" != ""; |