diff --git a/lix/nix/why-depends.cc b/lix/nix/why-depends.cc index 8d85abcd3..56cfb2a6e 100644 --- a/lix/nix/why-depends.cc +++ b/lix/nix/why-depends.cc @@ -3,6 +3,7 @@ #include "lix/libstore/fs-accessor.hh" #include "lix/libmain/shared.hh" #include "lix/libutil/error.hh" +#include "lix/libutil/generator.hh" #include "lix/libutil/result.hh" #include "why-depends.hh" @@ -99,9 +100,6 @@ try { co_return result::current_exception(); } -struct BailOut : BaseException -{}; - auto const inf = std::numeric_limits::max(); struct Node { @@ -114,29 +112,32 @@ struct Node bool visited = false; }; -static void printNode( +struct BailOut : BaseException +{}; + +static kj::Promise> printNode( Node & node, const std::string & firstPad, const std::string & tailPad, bool all, bool precise, Store & store, - AsyncIoRoot & aio, const StorePath & packagePath, const StorePath & dependencyPath, - std::map & graph + std::map & graph, + Strings & output ) -{ +try { auto pathS = store.printStorePath(node.path); assert(node.dist != inf); if (precise) { - logger->cout( - "%s%s%s%s" ANSI_NORMAL, - firstPad, - node.visited ? "\e[38;5;244m" : "", - firstPad != "" ? "→ " : "", - pathS + output.push_back( + fmt("%s%s%s%s" ANSI_NORMAL, + firstPad, + node.visited ? "\e[38;5;244m" : "", + firstPad != "" ? "→ " : "", + pathS) ); } @@ -145,8 +146,9 @@ static void printNode( } if (node.visited) { - return; + co_return result::success(); } + if (precise) { node.visited = true; } @@ -175,7 +177,7 @@ static void printNode( // FIXME: should use scanForReferences(). if (precise) { - hits = aio.blockOn(visitPath( + hits = TRY_AWAIT(visitPath( pathS, store, pathS, dependencyPath.hashPart(), hashes, packagePath, dependencyPath )); } @@ -187,11 +189,11 @@ static void printNode( for (auto & hit : hits[hash]) { bool first = hit == *hits[hash].begin(); - logger->cout( - "%s%s%s", - tailPad, - (first ? (last ? treeLast : treeConn) : (last ? treeNull : treeLine)), - hit + output.push_back( + fmt("%s%s%s", + tailPad, + (first ? (last ? treeLast : treeConn) : (last ? treeNull : treeLine)), + hit) ); if (!all) { break; @@ -200,29 +202,33 @@ static void printNode( if (!precise) { auto pathS = store.printStorePath(ref.second->path); - logger->cout( - "%s%s%s%s" ANSI_NORMAL, - firstPad, - ref.second->visited ? "\e[38;5;244m" : "", - last ? treeLast : treeConn, - pathS + output.push_back( + fmt("%s%s%s%s" ANSI_NORMAL, + firstPad, + ref.second->visited ? "\e[38;5;244m" : "", + last ? treeLast : treeConn, + pathS) ); node.visited = true; } - printNode( + TRY_AWAIT(printNode( *ref.second, tailPad + (last ? treeNull : treeLine), tailPad + (last ? treeNull : treeLine), all, precise, store, - aio, packagePath, dependencyPath, - graph - ); + graph, + output + )); } + + co_return result::success(); +} catch (...) { + co_return result::current_exception(); } struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions @@ -356,23 +362,30 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions 'dependency'). Print every edge on a path between `package` and `dependency`. */ RunPager pager; + if (!precise) { + logger->cout("%s", store->printStorePath(graph.at(packagePath).path)); + } + + Strings output; try { - if (!precise) { - logger->cout("%s", store->printStorePath(graph.at(packagePath).path)); - } - printNode( + aio().blockOn(printNode( graph.at(packagePath), "", "", all, precise, *store, - aio(), packagePath, dependencyPath, - graph - ); - } catch (BailOut & ) { } + graph, + output + )); + } catch (BailOut &) { + } + + for (auto & l : output) { + logger->cout("%s", l); + } } }; diff --git a/tests/functional/dependencies.builder0.sh b/tests/functional/dependencies.builder0.sh index 9b11576e0..feacf3d1d 100644 --- a/tests/functional/dependencies.builder0.sh +++ b/tests/functional/dependencies.builder0.sh @@ -5,6 +5,7 @@ mkdir $out echo $(cat $input1/foo)$(cat $input2/bar) > $out/foobar ln -s $input2 $out/reference-to-input-2 +ln -s $input3 $out/reference-to-input-3 # Self-reference. ln -s $out $out/self diff --git a/tests/functional/dependencies.nix b/tests/functional/dependencies.nix index 6463bcb32..d9e3e3f1f 100644 --- a/tests/functional/dependencies.nix +++ b/tests/functional/dependencies.nix @@ -20,9 +20,15 @@ let head -c 100k /dev/zero > $out/filler echo BAR > $out/bar echo ${input0} > $out/input0 + echo ${input3} > $out/input3 ''; }; + input3 = mkDerivation { + name = "dependencies-input-3"; + buildCommand = "mkdir $out; echo FOO > $out/foo"; + }; + fod_input = mkDerivation { name = "fod-input"; buildCommand = '' @@ -40,8 +46,10 @@ mkDerivation { builder = ./dependencies.builder0.sh + "/FOOBAR/../."; input1 = input1 + "/."; input2 = "${input2}/."; + input3 = "${input3}/."; input1_drv = input1; input2_drv = input2; + input3_drv = input3; input0_drv = input0; fod_input_drv = fod_input; meta.description = "Random test package"; diff --git a/tests/functional/export-graph.sh b/tests/functional/export-graph.sh index 1f6232a40..c1fb4d0a3 100644 --- a/tests/functional/export-graph.sh +++ b/tests/functional/export-graph.sh @@ -11,7 +11,7 @@ checkRef() { outPath=$(nix-build ./export-graph.nix -A 'foo."bar.runtimeGraph"' -o $TEST_ROOT/result) -test $(nix-store -q --references $TEST_ROOT/result | wc -l) = 3 || fail "bad nr of references" +test $(nix-store -q --references $TEST_ROOT/result | wc -l) = 4 || fail "bad nr of references" checkRef input-2 for i in $(cat $outPath); do checkRef $i; done diff --git a/tests/functional/why-depends.sh b/tests/functional/why-depends.sh index 9680bf80e..8103df666 100644 --- a/tests/functional/why-depends.sh +++ b/tests/functional/why-depends.sh @@ -10,6 +10,7 @@ nix why-depends --derivation --file ./dependencies.nix input2_drv input1_drv nix why-depends --file ./dependencies.nix input2_drv input1_drv nix-build ./dependencies.nix -A input0_drv -o dep +nix-build ./dependencies.nix -A input3_drv -o dep3 nix-build ./dependencies.nix -o toplevel FAST_WHY_DEPENDS_OUTPUT=$(nix why-depends ./toplevel ./dep) @@ -27,3 +28,14 @@ echo "$PRECISE_WHY_DEPENDS_OUTPUT" | grepQuiet reference-to-input-2 <<<"$PRECISE_WHY_DEPENDS_OUTPUT" sed -n '3p' | grep " →" | grepQuiet "dependencies-input-2" <<<"$PRECISE_WHY_DEPENDS_OUTPUT" sed -n '4p' | grepQuiet " └───input0: …" # in input-2, file input0 <<<"$PRECISE_WHY_DEPENDS_OUTPUT" sed -n '5p' | grep " →" | grepQuiet "dependencies-input-0" # is dependencies-input-0 referenced + +WHY_DEPENDS_SELF_REF="$(nix why-depends ./toplevel ./toplevel)" +<<<"$WHY_DEPENDS_SELF_REF" sed -n '1p' | grepQuiet "dependencies-top" +<<<"$WHY_DEPENDS_SELF_REF" sed -n '2p' | grep "└─" | grepQuiet "dependencies-top" +test -z "$(<<<"$WHY_DEPENDS_SELF_REF" sed -n '3p')" + +WHY_DEPENDS_ALL="$(nix why-depends ./toplevel ./dep3 --all)" +<<<"$WHY_DEPENDS_ALL" sed -n '1p' | grep -v "└─" | grepQuiet "dependencies-top" +<<<"$WHY_DEPENDS_ALL" sed -n '2p' | grep "├─" | grepQuiet "input-3" +<<<"$WHY_DEPENDS_ALL" sed -n '3p' | grep "└─" | grepQuiet "input-2" +<<<"$WHY_DEPENDS_ALL" sed -n '4p' | grep " └─" | grepQuiet "input-3"