From dd7c2e0695b02639d8fe6c7bc050da14373b9513 Mon Sep 17 00:00:00 2001
From: regnat <rg@regnat.ovh>
Date: Wed, 19 Jan 2022 14:15:45 +0100
Subject: [PATCH] Make `nix why-depends` quieter by default

Unless `--precise` is passed, make `nix why-depends` only show the
dependencies between the store paths, without introspecting them to
find the actual references.

This also makes it ~3x faster
---
 src/nix/why-depends.cc         | 27 +++++++++++++++++++++------
 tests/dependencies.builder0.sh |  2 +-
 tests/gc.sh                    |  4 ++--
 tests/why-depends.sh           | 12 ++++++++++--
 4 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/src/nix/why-depends.cc b/src/nix/why-depends.cc
index dd43bd1c3..74377c912 100644
--- a/src/nix/why-depends.cc
+++ b/src/nix/why-depends.cc
@@ -31,6 +31,7 @@ struct CmdWhyDepends : SourceExprCommand
 {
     std::string _package, _dependency;
     bool all = false;
+    bool precise = false;
 
     CmdWhyDepends()
     {
@@ -56,6 +57,12 @@ struct CmdWhyDepends : SourceExprCommand
             .description = "Show all edges in the dependency graph leading from *package* to *dependency*, rather than just a shortest path.",
             .handler = {&all, true},
         });
+
+        addFlag({
+            .longName = "precise",
+            .description = "For each edge of the graph, inspect the parent node to display the exact location in the path that causes the dependency",
+            .handler = {&precise, true},
+        });
     }
 
     std::string description() override
@@ -158,11 +165,19 @@ struct CmdWhyDepends : SourceExprCommand
             auto pathS = store->printStorePath(node.path);
 
             assert(node.dist != inf);
-            logger->cout("%s%s%s%s" ANSI_NORMAL,
-                firstPad,
-                node.visited ? "\e[38;5;244m" : "",
-                firstPad != "" ? "→ " : "",
-                pathS);
+            if (precise) {
+                logger->cout("%s%s%s%s" ANSI_NORMAL,
+                    firstPad,
+                    node.visited ? "\e[38;5;244m" : "",
+                    firstPad != "" ? "→ " : "",
+                    pathS);
+            } else {
+                logger->cout("%s%s%s%s" ANSI_NORMAL,
+                    firstPad,
+                    node.visited ? "\e[38;5;244m" : "",
+                    firstPad != "" ? treeLast : "",
+                    pathS);
+            }
 
             if (node.path == dependencyPath && !all
                 && packagePath != dependencyPath)
@@ -237,7 +252,7 @@ struct CmdWhyDepends : SourceExprCommand
 
             // FIXME: should use scanForReferences().
 
-            visitPath(pathS);
+            if (precise) visitPath(pathS);
 
             for (auto & ref : refs) {
                 std::string hash(ref.second->path.hashPart());
diff --git a/tests/dependencies.builder0.sh b/tests/dependencies.builder0.sh
index c37bf909a..9b11576e0 100644
--- a/tests/dependencies.builder0.sh
+++ b/tests/dependencies.builder0.sh
@@ -4,7 +4,7 @@
 mkdir $out
 echo $(cat $input1/foo)$(cat $input2/bar) > $out/foobar
 
-ln -s $input2 $out/input-2
+ln -s $input2 $out/reference-to-input-2
 
 # Self-reference.
 ln -s $out $out/self
diff --git a/tests/gc.sh b/tests/gc.sh
index a736b63db..ad09a8b39 100644
--- a/tests/gc.sh
+++ b/tests/gc.sh
@@ -18,7 +18,7 @@ if nix-store --gc --print-dead | grep -E $outPath$; then false; fi
 
 nix-store --gc --print-dead
 
-inUse=$(readLink $outPath/input-2)
+inUse=$(readLink $outPath/reference-to-input-2)
 if nix-store --delete $inUse; then false; fi
 test -e $inUse
 
@@ -35,7 +35,7 @@ nix-collect-garbage
 
 # Check that the root and its dependencies haven't been deleted.
 cat $outPath/foobar
-cat $outPath/input-2/bar
+cat $outPath/reference-to-input-2/bar
 
 # Check that the derivation has been GC'd.
 if test -e $drvPath; then false; fi
diff --git a/tests/why-depends.sh b/tests/why-depends.sh
index 11b54b5b6..c12941e76 100644
--- a/tests/why-depends.sh
+++ b/tests/why-depends.sh
@@ -9,5 +9,13 @@ cd $TEST_HOME
 nix-build ./dependencies.nix -A input0_drv -o dep
 nix-build ./dependencies.nix -o toplevel
 
-nix why-depends ./toplevel ./dep |
-    grep input-2
+FAST_WHY_DEPENDS_OUTPUT=$(nix why-depends ./toplevel ./dep)
+PRECISE_WHY_DEPENDS_OUTPUT=$(nix why-depends ./toplevel ./dep --precise)
+
+# Both outputs should show that `input-2` is in the dependency chain
+echo "$FAST_WHY_DEPENDS_OUTPUT" | grep -q input-2
+echo "$PRECISE_WHY_DEPENDS_OUTPUT" | grep -q input-2
+
+# But only the “precise” one should refere to `reference-to-input-2`
+echo "$FAST_WHY_DEPENDS_OUTPUT" | (! grep -q reference-to-input-2)
+echo "$PRECISE_WHY_DEPENDS_OUTPUT" | grep -q reference-to-input-2