Something went wrong. Try again.
lol
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687/** 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 (lib) concatMapStringsSep isList isAttrs substring attrValues concatLists const elem foldl' generators id mapAttrs ;in
rec { inherit (builtins) trace addErrorContext unsafeGetAttrPos ;
# -- TRACING --
/** Conditionally trace the supplied message, based on a predicate.
# Inputs
`pred`
: Predicate to check
`msg`
: Message that should be traced
`x`
: Value to return
# Type
``` traceIf :: Bool -> String -> a -> a ```
# Examples :::{.example} ## `lib.debug.traceIf` usage example
```nix traceIf true "hello" 3 trace: hello => 3 ```
::: */ traceIf = pred: msg: x: if pred then trace msg x else x;
/** Trace the supplied value after applying a function to it, and return the original value.
# Inputs
`f`
: Function to apply
`x`
: Value to trace and return
# Type
``` traceValFn :: (a -> b) -> a -> a ```
# Examples :::{.example} ## `lib.debug.traceValFn` usage example
```nix traceValFn (v: "mystring ${v}") "foo" trace: mystring foo => "foo" ```
::: */ traceValFn = f: x: trace (f x) x;
/** Trace the supplied value and return it.
# Inputs
`x`
: Value to trace and return
# Type
``` traceVal :: a -> a ```
# Examples :::{.example} ## `lib.debug.traceVal` usage example
```nix traceVal 42 # trace: 42 => 42 ```
::: */ traceVal = traceValFn id;
/** `builtins.trace`, but the value is `builtins.deepSeq`ed first.
# Inputs
`x`
: The value to trace
`y`
: The value to return
# Type
``` traceSeq :: a -> b -> b ```
# Examples :::{.example} ## `lib.debug.traceSeq` usage example
```nix trace { a.b.c = 3; } null trace: { a = <thunk>; } => 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 evaluate down to depth n. This is very useful because lots of `traceSeq` usages lead to an infinite recursion.
# Inputs
`depth`
: 1\. Function argument
`x`
: 2\. Function argument
`y`
: 3\. Function argument
# Type
``` traceSeqN :: Int -> a -> b -> b ```
# Examples :::{.example} ## `lib.debug.traceSeqN` usage example
```nix traceSeqN 2 { a.b.c = 3; } null trace: { a = { b = {…}; }; } => null ```
::: */ traceSeqN = depth: x: y: 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;
/** A combination of `traceVal` and `traceSeq` that applies a provided function to the value to be traced after `deepSeq`ing it.
# Inputs
`f`
: Function to apply
`v`
: Value to trace
# Type
``` traceValSeqFn :: (a -> b) -> a -> a ```
# Examples :::{.example} ## `lib.debug.traceValSeqFn` usage example
```nix traceValSeqFn (v: v // { d = "foo";}) { a.b.c = 3; } trace: { a = { b = { c = 3; }; }; d = "foo"; } => { a = { ... }; }
::: */ traceValSeqFn = f: v: traceValFn f (builtins.deepSeq v v);
/** A combination of `traceVal` and `traceSeq`.
# Inputs
`v`
: Value to trace
# Type
``` traceValSeq :: a -> a ```
# Examples :::{.example} ## `lib.debug.traceValSeq` usage example
```nix traceValSeq { a.b.c = 3; } trace: { a = { b = { c = 3; }; }; } => { a = { ... }; } ```
::: */ traceValSeq = traceValSeqFn id;
/** A combination of `traceVal` and `traceSeqN` that applies a provided function to the value to be traced.
# Inputs
`f`
: Function to apply
`depth`
: 2\. Function argument
`v`
: Value to trace
# Type
``` traceValSeqNFn :: (a -> b) -> Int -> a -> a ```
# Examples :::{.example} ## `lib.debug.traceValSeqNFn` usage example
```nix traceValSeqNFn (v: v // { d = "foo";}) 2 { a.b.c = 3; } trace: { a = { b = {…}; }; d = "foo"; } => { a = { ... }; } ```
::: */ traceValSeqNFn = f: depth: v: traceSeqN depth (f v) v;
/** A combination of `traceVal` and `traceSeqN`.
# Inputs
`depth`
: 1\. Function argument
`v`
: Value to trace
# Type
``` traceValSeqN :: Int -> a -> a ```
# Examples :::{.example} ## `lib.debug.traceValSeqN` usage example
```nix traceValSeqN 2 { a.b.c = 3; } trace: { a = { b = {…}; }; } => { a = { ... }; } ```
::: */ traceValSeqN = traceValSeqNFn id;
/** Trace the input and output of a function `f` named `name`, both down to `depth`.
This is useful for adding around a function call, to see the before/after of values as they are transformed.
# Inputs
`depth`
: 1\. Function argument
`name`
: 2\. Function argument
`f`
: 3\. Function argument
`v`
: 4\. Function argument
# Type
``` traceFnSeqN :: Int -> String -> (a -> b) -> a -> b ```
# Examples :::{.example} ## `lib.debug.traceFnSeqN` usage example
```nix traceFnSeqN 2 "id" (x: x) { a.b.c = 3; } trace: { fn = "id"; from = { a.b = {…}; }; to = { a.b = {…}; }; } => { a = { ... }; } ```
::: */ traceFnSeqN = depth: name: f: v: let res = f v; in lib.traceSeqN (depth + 1) { fn = name; from = v; to = res; } res;
# -- TESTING --
/** Evaluates 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, result}`,
- expected - What was passed as `expected` - result - The actual `result` of the test
Used for regression testing of the functions in lib; see tests.nix for more examples.
Important: Only attributes that start with `test` are executed.
- If you want to run only a subset of the tests add the attribute `tests = ["testName"];`
# Inputs
`tests`
: Tests to run
# Type
``` runTests :: { tests :: [String]; ${testName} :: { expr :: a; expected :: a; }; } -> [ { name :: String; expected :: a; result :: a; } ] ```
# Examples :::{.example} ## `lib.debug.runTests` usage example
```nix runTests { testAndOk = { expr = lib.and true false; expected = false; }; testAndFail = { expr = lib.and true false; expected = true; }; } -> [ { name = "testAndFail"; expected = true; result = false; } ] ```
::: */ runTests = tests: concatLists ( attrValues ( mapAttrs ( name: test: 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 ) );
/** Pretty-print a list of test failures.
This takes an attribute set containing `failures` (a list of test failures produced by `runTests`) and pretty-prints each failing test, before throwing an error containing the raw test data as JSON.
If the input list is empty, `null` is returned.
# Inputs
`failures`
: A list of test failures (produced `runTests`), each containing `name`, `expected`, and `result` attributes.
# Type
``` throwTestFailures :: { failures = [ { name :: String; expected :: a; result :: a; } ]; } -> Null ```
# Examples :::{.example}
## `lib.debug.throwTestFailures` usage example
```nix throwTestFailures { failures = [ { name = "testDerivation"; expected = derivation { name = "a"; builder = "bash"; system = "x86_64-linux"; }; result = derivation { name = "b"; builder = "bash"; system = "x86_64-linux"; }; } ]; } -> trace: FAIL testDerivation: Expected: <derivation a> Result: <derivation b>
error: … while evaluating the file '...':
… caused by explicit throw at /nix/store/.../lib/debug.nix:528:7: 527| in 528| throw ( | ^ 529| builtins.seq traceFailures (
error: 1 tests failed: - testDerivation
[{"expected":"/nix/store/xh7kyqp69mxkwspmi81a94m9xx74r8dr-a","name":"testDerivation","result":"/nix/store/503l84nir4zw57d1shfhai25bxxn16c6-b"}] null ```
::: */ throwTestFailures = { failures, description ? "tests", ... }: if failures == [ ] then null else let toPretty = value: # Thanks to @Ma27 for this: # # > The `unsafeDiscardStringContext` is useful when the `toPretty` # > stumbles upon a derivation that would be realized without it (I # > ran into the problem when writing a test for a flake helper where # > I creating a bunch of "mock" derivations for different systems # > and Nix then tried to build those when the error-string got # > forced). # # See: https://github.com/NixOS/nixpkgs/pull/416207#discussion_r2145942389 builtins.unsafeDiscardStringContext (generators.toPretty { allowPrettyValues = true; } value);
failureToPretty = failure: '' FAIL ${toPretty failure.name}: Expected: ${toPretty failure.expected}
Result: ${toPretty failure.result} '';
traceFailures = foldl' (_accumulator: failure: traceVal (failureToPretty failure)) null failures; in throw ( builtins.seq traceFailures ( "${builtins.toString (builtins.length failures)} ${description} failed:\n- " + (concatMapStringsSep "\n- " (failure: failure.name) failures) + "\n\n" + builtins.toJSON failures ) );
/** Create a test assuming that list elements are `true`.
# Inputs
`expr`
: 1\. Function argument
# Examples :::{.example} ## `lib.debug.testAllTrue` usage example
```nix { testX = allTrue [ true ]; } ```
::: */ testAllTrue = expr: { inherit expr; expected = map (x: true) expr; };}