From 49263f154a520602c8f575bab642405825bf3f59 Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Tue, 1 Jul 2025 23:55:31 +0200 Subject: [PATCH] why-depends: initialize internal graph data from std::map The Node struct should become an implementation detail when moving this into libstore. A map from a node to its direct references is more intuitive here. Change-Id: I9fddce6b398b8bb97834e5586bee72b244885fdd --- lix/nix/why-depends.cc | 102 ++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 41 deletions(-) diff --git a/lix/nix/why-depends.cc b/lix/nix/why-depends.cc index 03aa90ebc..fb1c9ee00 100644 --- a/lix/nix/why-depends.cc +++ b/lix/nix/why-depends.cc @@ -7,6 +7,7 @@ #include "lix/libutil/result.hh" #include "why-depends.hh" +#include #include namespace nix { @@ -229,6 +230,61 @@ try { co_return result::current_exception(); } +static std::map mkGraph( + const StorePath & packagePath, + const StorePath & dependencyPath, + const std::map & graph, + Store & store, + bool all, + bool precise +) +{ + std::map graph_data; + for (auto & [path, dependencies] : graph) { + graph_data.emplace( + path, + Node{ + .path = path, + .dependencies = dependencies, + .dist = path == dependencyPath ? std::optional(0) : std::nullopt, + } + ); + } + + for (auto & node : graph_data) { + for (auto & ref : node.second.dependencies) { + graph_data.find(ref)->second.dependents.insert(node.first); + } + } + + /* Run Dijkstra's shortest path algorithm to get the distance + of every path in the closure to 'dependency'. */ + std::priority_queue queue; + + queue.push(&graph_data.at(dependencyPath)); + auto const inf = std::numeric_limits::max(); + + while (!queue.empty()) { + auto & node = *queue.top(); + queue.pop(); + + for (auto & rref : node.dependents) { + auto & node2 = graph_data.at(rref); + auto dist = node.dist.transform([](auto n) { return n + 1; }); + if (dist.value_or(inf) < node2.dist.value_or(inf)) { + node2.dist = dist; + node2.prev = &node; + if (!node2.queued) { + node2.queued = true; + queue.push(&node2); + } + } + } + } + + return graph_data; +} + struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions { std::string _package, _dependency; @@ -316,49 +372,13 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions auto accessor = store->getFSAccessor(); - std::map graph; - - for (auto & path : closure) - graph.emplace( - path, - Node{ - .path = path, - .dependencies = aio().blockOn(store->queryPathInfo(path))->references, - .dist = path == dependencyPath ? std::optional(0) : std::nullopt - } - ); - - // Transpose the graph. - for (auto & node : graph) - for (auto & ref : node.second.dependencies) { - graph.find(ref)->second.dependents.insert(node.first); - } - - /* Run Dijkstra's shortest path algorithm to get the distance - of every path in the closure to 'dependency'. */ - std::priority_queue queue; - - queue.push(&graph.at(dependencyPath)); - auto const inf = std::numeric_limits::max(); - - while (!queue.empty()) { - auto & node = *queue.top(); - queue.pop(); - - for (auto & rref : node.dependents) { - auto & node2 = graph.at(rref); - auto dist = node.dist.transform([](auto n) { return n + 1; }); - if (dist.value_or(inf) < node2.dist.value_or(inf)) { - node2.dist = dist; - node2.prev = &node; - if (!node2.queued) { - node2.queued = true; - queue.push(&node2); - } - } - } + std::map graphData; + for (auto & path : closure) { + graphData.emplace(path, aio().blockOn(store->queryPathInfo(path))->references); } + auto graph = mkGraph(packagePath, dependencyPath, graphData, *store, all, precise); + /* Print the subgraph of nodes that have 'dependency' in their closure (i.e., that have a non-infinite distance to 'dependency'). Print every edge on a path between `package`