why-depends: extract printNode

Change-Id: Ia0ba08745b9498fdbcc4231f91bf3d45afbe8373
This commit is contained in:
Maximilian Bosch
2025-07-07 11:44:17 +00:00
parent c2693327d9
commit 1d6c8bff77
+139 -93
View File
@@ -33,7 +33,7 @@ static kj::Promise<Result<std::map<std::string, Strings>>> visitPath(
const Path & p, const Path & p,
Store & store, Store & store,
const Path & pathS, const Path & pathS,
std::string_view & dependencyPathHash, std::string_view dependencyPathHash,
const std::set<std::string> & hashes, const std::set<std::string> & hashes,
const StorePath & from, const StorePath & from,
const StorePath & to const StorePath & to
@@ -99,6 +99,132 @@ try {
co_return result::current_exception(); co_return result::current_exception();
} }
struct BailOut : BaseException
{};
auto const inf = std::numeric_limits<size_t>::max();
struct Node
{
StorePath path;
StorePathSet refs;
StorePathSet rrefs;
size_t dist = inf;
Node * prev = nullptr;
bool queued = false;
bool visited = false;
};
static void 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<StorePath, Node> & graph
)
{
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
);
}
if (node.path == dependencyPath && !all && packagePath != dependencyPath) {
throw BailOut();
}
if (node.visited) {
return;
}
if (precise) {
node.visited = true;
}
/* Sort the references by distance to `dependency` to
ensure that the shortest path is printed first. */
std::multimap<size_t, Node *> refs;
std::set<std::string> hashes;
for (auto & ref : node.refs) {
if (ref == node.path && packagePath != dependencyPath) {
continue;
}
auto & node2 = graph.at(ref);
if (node2.dist == inf) {
continue;
}
refs.emplace(node2.dist, &node2);
hashes.insert(std::string(node2.path.hashPart()));
}
/* For each reference, find the files and symlinks that
contain the reference. */
std::map<std::string, Strings> hits;
// FIXME: should use scanForReferences().
if (precise) {
hits = aio.blockOn(visitPath(
pathS, store, pathS, dependencyPath.hashPart(), hashes, packagePath, dependencyPath
));
}
for (auto & ref : refs) {
std::string hash(ref.second->path.hashPart());
bool last = all ? ref == *refs.rbegin() : true;
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
);
if (!all) {
break;
}
}
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
);
node.visited = true;
}
printNode(
*ref.second,
tailPad + (last ? treeNull : treeLine),
tailPad + (last ? treeNull : treeLine),
all,
precise,
store,
aio,
packagePath,
dependencyPath,
graph
);
}
}
struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
{ {
std::string _package, _dependency; std::string _package, _dependency;
@@ -181,25 +307,11 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
} }
auto dependencyPath = *optDependencyPath; auto dependencyPath = *optDependencyPath;
auto dependencyPathHash = dependencyPath.hashPart();
logger->pause(); // FIXME logger->pause(); // FIXME
auto accessor = store->getFSAccessor(); auto accessor = store->getFSAccessor();
auto const inf = std::numeric_limits<size_t>::max();
struct Node
{
StorePath path;
StorePathSet refs;
StorePathSet rrefs;
size_t dist = inf;
Node * prev = nullptr;
bool queued = false;
bool visited = false;
};
std::map<StorePath, Node> graph; std::map<StorePath, Node> graph;
for (auto & path : closure) for (auto & path : closure)
@@ -243,89 +355,23 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
closure (i.e., that have a non-infinite distance to closure (i.e., that have a non-infinite distance to
'dependency'). Print every edge on a path between `package` 'dependency'). Print every edge on a path between `package`
and `dependency`. */ and `dependency`. */
std::function<void(Node &, const std::string &, const std::string &)> printNode;
struct BailOut : BaseException { };
printNode = [&](Node & node, const std::string & firstPad, const std::string & tailPad) {
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);
}
if (node.path == dependencyPath && !all
&& packagePath != dependencyPath)
throw BailOut();
if (node.visited) return;
if (precise) node.visited = true;
/* Sort the references by distance to `dependency` to
ensure that the shortest path is printed first. */
std::multimap<size_t, Node *> refs;
std::set<std::string> hashes;
for (auto & ref : node.refs) {
if (ref == node.path && packagePath != dependencyPath) continue;
auto & node2 = graph.at(ref);
if (node2.dist == inf) continue;
refs.emplace(node2.dist, &node2);
hashes.insert(std::string(node2.path.hashPart()));
}
/* For each reference, find the files and symlinks that
contain the reference. */
std::map<std::string, Strings> hits;
// FIXME: should use scanForReferences().
if (precise) {
hits = aio().blockOn(visitPath(
pathS, *store, pathS, dependencyPathHash, hashes, packagePath, dependencyPath
));
}
for (auto & ref : refs) {
std::string hash(ref.second->path.hashPart());
bool last = all ? ref == *refs.rbegin() : true;
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);
if (!all) break;
}
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);
node.visited = true;
}
printNode(*ref.second,
tailPad + (last ? treeNull : treeLine),
tailPad + (last ? treeNull : treeLine));
}
};
RunPager pager; RunPager pager;
try { try {
if (!precise) { if (!precise) {
logger->cout("%s", store->printStorePath(graph.at(packagePath).path)); logger->cout("%s", store->printStorePath(graph.at(packagePath).path));
} }
printNode(graph.at(packagePath), "", ""); printNode(
graph.at(packagePath),
"",
"",
all,
precise,
*store,
aio(),
packagePath,
dependencyPath,
graph
);
} catch (BailOut & ) { } } catch (BailOut & ) { }
} }
}; };