libstore/path-tree: allow passing a custom accessor
If none is given, we fall back to whatever accessor we get from the store. To display which paths actually contain the references leading to e.g. a cycle or triggering a disallowedRequisites error, we'd potentially have to look into the chroot from the previously finished build. This behavior should not be part of the local accessor by default, but part of a "special" accessor. This change allows using such an accessor for `genGraphString()`. Now that we inject the accessor from the outside, we have to mock it anyways in the tests. Hence, this also adds a testcase for the precise=True case. Change-Id: I58465fb944776c2b0262ba054d1f296ed2ae3406
This commit is contained in:
+23
-10
@@ -37,13 +37,13 @@ static kj::Promise<Result<std::map<std::string, Strings>>> visitPath(
|
||||
std::string_view dependencyPathHash,
|
||||
const std::set<std::string> & hashes,
|
||||
const StorePath & from,
|
||||
const StorePath & to
|
||||
const StorePath & to,
|
||||
const ref<FSAccessor> & accessor
|
||||
)
|
||||
try {
|
||||
/* For each reference, find the files and symlinks that
|
||||
contain the reference. */
|
||||
std::map<std::string, Strings> hits;
|
||||
auto accessor = store.getFSAccessor();
|
||||
auto st = TRY_AWAIT(accessor->stat(p));
|
||||
|
||||
auto p2 = p == pathS ? "/" : std::string(p, pathS.size() + 1);
|
||||
@@ -55,9 +55,9 @@ try {
|
||||
if (st.type == FSAccessor::Type::tDirectory) {
|
||||
auto names = TRY_AWAIT(accessor->readDirectory(p));
|
||||
for (auto & name : names) {
|
||||
auto found = TRY_AWAIT(
|
||||
visitPath(p + "/" + name, store, pathS, dependencyPathHash, hashes, from, to)
|
||||
);
|
||||
auto found = TRY_AWAIT(visitPath(
|
||||
p + "/" + name, store, pathS, dependencyPathHash, hashes, from, to, accessor
|
||||
));
|
||||
hits.merge(found);
|
||||
}
|
||||
} else if (st.type == FSAccessor::Type::tRegular) {
|
||||
@@ -124,7 +124,8 @@ static kj::Promise<Result<void>> printNode(
|
||||
const StorePath & packagePath,
|
||||
const StorePath & dependencyPath,
|
||||
std::map<StorePath, Node> & graph,
|
||||
Strings & output
|
||||
Strings & output,
|
||||
ref<FSAccessor> accessor
|
||||
)
|
||||
try {
|
||||
auto pathS = store.printStorePath(node.path);
|
||||
@@ -178,7 +179,14 @@ try {
|
||||
|
||||
if (precise) {
|
||||
hits = TRY_AWAIT(visitPath(
|
||||
pathS, store, pathS, dependencyPath.hashPart(), hashes, packagePath, dependencyPath
|
||||
pathS,
|
||||
store,
|
||||
pathS,
|
||||
dependencyPath.hashPart(),
|
||||
hashes,
|
||||
packagePath,
|
||||
dependencyPath,
|
||||
accessor
|
||||
));
|
||||
}
|
||||
|
||||
@@ -224,7 +232,8 @@ try {
|
||||
packagePath,
|
||||
dependencyPath,
|
||||
graph,
|
||||
output
|
||||
output,
|
||||
accessor
|
||||
));
|
||||
}
|
||||
|
||||
@@ -294,10 +303,12 @@ kj::Promise<Result<std::string>> genGraphString(
|
||||
const std::map<StorePath, StorePathSet> & graphData,
|
||||
Store & store,
|
||||
bool all,
|
||||
bool precise
|
||||
bool precise,
|
||||
std::optional<ref<FSAccessor>> maybeAccessor
|
||||
)
|
||||
try {
|
||||
auto graph = mkGraph(start, to, graphData, store, all, precise);
|
||||
auto accessor = maybeAccessor ? *maybeAccessor : store.getFSAccessor();
|
||||
|
||||
Strings output;
|
||||
if (!precise) {
|
||||
@@ -305,7 +316,9 @@ try {
|
||||
}
|
||||
|
||||
try {
|
||||
TRY_AWAIT(printNode(graph.at(start), "", "", all, precise, store, start, to, graph, output));
|
||||
TRY_AWAIT(printNode(
|
||||
graph.at(start), "", "", all, precise, store, start, to, graph, output, accessor
|
||||
));
|
||||
} catch (BailOut &) {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
/// @file
|
||||
|
||||
#include "fs-accessor.hh"
|
||||
#include "lix/libutil/result.hh"
|
||||
#include "path.hh"
|
||||
#include "store-api.hh"
|
||||
@@ -15,6 +16,7 @@ kj::Promise<Result<std::string>> genGraphString(
|
||||
const std::map<StorePath, StorePathSet> & graphData,
|
||||
Store & store,
|
||||
bool all,
|
||||
bool precise
|
||||
bool precise,
|
||||
std::optional<ref<FSAccessor>> accessor = std::nullopt
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,64 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "lix/libstore/path-tree.hh"
|
||||
#include "lix/libstore/fs-accessor.hh"
|
||||
#include "lix/libstore/nar-accessor.hh"
|
||||
#include "lix/libstore/path.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libutil/async.hh"
|
||||
#include "lix/libutil/ref.hh"
|
||||
#include "lix/libutil/json.hh"
|
||||
|
||||
namespace nix {
|
||||
static ref<FSAccessor> makeMockAccessor()
|
||||
{
|
||||
JSON nix = JSON::object();
|
||||
nix["type"] = "directory";
|
||||
|
||||
JSON store = JSON::object();
|
||||
nix["entries"] = JSON::object();
|
||||
|
||||
store["type"] = "directory";
|
||||
store["entries"] = JSON::object();
|
||||
|
||||
const std::string sshContent =
|
||||
"I do link to /nix/store/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-glibc-2.40-66/lib/libc.so.6 in "
|
||||
"here";
|
||||
const auto narOffset = 2342ul;
|
||||
|
||||
auto openssh = JSON::object();
|
||||
openssh["type"] = "directory";
|
||||
openssh["entries"] = JSON::object();
|
||||
openssh["entries"]["bin"] = JSON::object();
|
||||
openssh["entries"]["bin"]["type"] = "directory";
|
||||
openssh["entries"]["bin"]["entries"] = JSON::object();
|
||||
openssh["entries"]["bin"]["entries"]["ssh"] = JSON::object();
|
||||
openssh["entries"]["bin"]["entries"]["ssh"]["type"] = "regular";
|
||||
openssh["entries"]["bin"]["entries"]["ssh"]["size"] = sshContent.size();
|
||||
openssh["entries"]["bin"]["entries"]["ssh"]["narOffset"] = narOffset;
|
||||
store["entries"]["hr8lmmjmd1jk6s3p5ymggyk4am7n2lmb-openssh-10.0p2"] = openssh;
|
||||
|
||||
nix["entries"]["store"] = store;
|
||||
|
||||
JSON listing = JSON::object();
|
||||
listing["type"] = "directory";
|
||||
listing["entries"] = JSON::object();
|
||||
listing["entries"]["nix"] = nix;
|
||||
|
||||
return makeLazyNarAccessor(
|
||||
listing.dump(),
|
||||
[narOffset, sshContent](uint64_t offset, uint64_t length) {
|
||||
if (offset == narOffset) {
|
||||
assert(length <= sshContent.size());
|
||||
return sshContent.substr(0, length);
|
||||
} else {
|
||||
throw Error(
|
||||
"Invalid offset '%llu' in mock NAR (looking for: %llu)", offset, narOffset
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST(PathTree, simple)
|
||||
{
|
||||
AsyncIoRoot aio;
|
||||
@@ -19,7 +73,7 @@ TEST(PathTree, simple)
|
||||
graph.insert({parent, {child}});
|
||||
|
||||
auto graph_data =
|
||||
aio.blockOn(genGraphString(parent, child, graph, *store, false, false));
|
||||
aio.blockOn(genGraphString(parent, child, graph, *store, false, false, makeMockAccessor()));
|
||||
|
||||
// clang-format off
|
||||
ASSERT_EQ(
|
||||
@@ -30,6 +84,32 @@ TEST(PathTree, simple)
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
TEST(PathTree, precise)
|
||||
{
|
||||
AsyncIoRoot aio;
|
||||
|
||||
auto store = aio.blockOn(openStore("dummy://"));
|
||||
|
||||
auto parent = StorePath{"hr8lmmjmd1jk6s3p5ymggyk4am7n2lmb-openssh-10.0p2"};
|
||||
auto child = StorePath{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-glibc-2.40-66"};
|
||||
|
||||
std::map<StorePath, StorePathSet> graph;
|
||||
graph.insert({child, {}});
|
||||
graph.insert({parent, {child}});
|
||||
|
||||
auto graph_data =
|
||||
aio.blockOn(genGraphString(parent, child, graph, *store, false, true, makeMockAccessor()));
|
||||
|
||||
// clang-format off
|
||||
ASSERT_EQ(
|
||||
graph_data,
|
||||
"/nix/store/hr8lmmjmd1jk6s3p5ymggyk4am7n2lmb-openssh-10.0p2\x1B[0m\n"
|
||||
"└───bin/ssh: …I do link to /nix/store/\x1B[32;1maaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1B[0m-glibc-2.40-66/lib/libc.so.6 in …\n"
|
||||
" \x1B[0m→ /nix/store/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-glibc-2.40-66\x1B[0m"
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
TEST(PathTree, all)
|
||||
{
|
||||
AsyncIoRoot aio;
|
||||
@@ -54,7 +134,7 @@ TEST(PathTree, all)
|
||||
// clang-format on
|
||||
|
||||
auto graph_data =
|
||||
aio.blockOn(genGraphString(parent, child, graph, *store, true, false));
|
||||
aio.blockOn(genGraphString(parent, child, graph, *store, true, false, makeMockAccessor()));
|
||||
ASSERT_EQ(graph_data, expected);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user