summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/debug.nix184
-rw-r--r--lib/default.nix11
-rw-r--r--lib/modules.nix4
-rw-r--r--lib/trivial.nix11
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" != "";