1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-12 12:01:05 +01:00

Deduplicate listNar and MemorySourceAccessor::File

`listNar` did the not-so-pretty thing of going straight to JSON. Now it
uses `MemorySourceAccessor::File`, or rather variations of it, to go to
a C++ data type first, and only JSON second.

To accomplish this we add some type parameters to the `File` data type.
Actually, we need to do two rounds of this, because shallow NAR
listings. There is `FileT` and `DirectoryT` accordingly.
This commit is contained in:
John Ericson 2025-11-19 17:16:07 -05:00
parent ac36d74b66
commit c4906741a1
8 changed files with 246 additions and 101 deletions

View file

@ -272,41 +272,39 @@ GetNarBytes seekableGetNarBytes(const Path & path)
};
}
using nlohmann::json;
template<bool deep>
using ListNarResult = std::conditional_t<deep, NarListing, ShallowNarListing>;
json listNar(SourceAccessor & accessor, const CanonPath & path, bool recurse)
template<bool deep>
static ListNarResult<deep> listNarImpl(SourceAccessor & accessor, const CanonPath & path)
{
auto st = accessor.lstat(path);
json obj = json::object();
switch (st.type) {
case SourceAccessor::Type::tRegular:
obj["type"] = "regular";
if (st.fileSize)
obj["size"] = *st.fileSize;
if (st.isExecutable)
obj["executable"] = true;
if (st.narOffset && *st.narOffset)
obj["narOffset"] = *st.narOffset;
break;
case SourceAccessor::Type::tDirectory:
obj["type"] = "directory";
{
obj["entries"] = json::object();
json & res2 = obj["entries"];
for (const auto & [name, type] : accessor.readDirectory(path)) {
if (recurse) {
res2[name] = listNar(accessor, path / name, true);
} else
res2[name] = json::object();
return typename ListNarResult<deep>::Regular{
.executable = st.isExecutable,
.contents =
NarListingRegularFile{
.fileSize = st.fileSize,
.narOffset = st.narOffset && *st.narOffset ? st.narOffset : std::nullopt,
},
};
case SourceAccessor::Type::tDirectory: {
typename ListNarResult<deep>::Directory dir;
for (const auto & [name, type] : accessor.readDirectory(path)) {
if constexpr (deep) {
dir.entries.emplace(name, listNarImpl<true>(accessor, path / name));
} else {
dir.entries.emplace(name, fso::Opaque{});
}
}
break;
return dir;
}
case SourceAccessor::Type::tSymlink:
obj["type"] = "symlink";
obj["target"] = accessor.readLink(path);
break;
return typename ListNarResult<deep>::Symlink{
.target = accessor.readLink(path),
};
case SourceAccessor::Type::tBlock:
case SourceAccessor::Type::tChar:
case SourceAccessor::Type::tSocket:
@ -314,7 +312,64 @@ json listNar(SourceAccessor & accessor, const CanonPath & path, bool recurse)
case SourceAccessor::Type::tUnknown:
assert(false); // cannot happen for NARs
}
return obj;
}
NarListing listNarDeep(SourceAccessor & accessor, const CanonPath & path)
{
return listNarImpl<true>(accessor, path);
}
ShallowNarListing listNarShallow(SourceAccessor & accessor, const CanonPath & path)
{
return listNarImpl<false>(accessor, path);
}
template<typename Listing>
static void to_json_impl(nlohmann::json & j, const Listing & listing)
{
std::visit(
overloaded{
[&](const typename Listing::Regular & r) {
j = nlohmann::json::object();
j["type"] = "regular";
if (r.contents.fileSize)
j["size"] = *r.contents.fileSize;
if (r.executable)
j["executable"] = true;
if (r.contents.narOffset)
j["narOffset"] = *r.contents.narOffset;
},
[&](const typename Listing::Directory & d) {
j = nlohmann::json::object();
j["type"] = "directory";
j["entries"] = nlohmann::json::object();
for (const auto & [name, child] : d.entries) {
if constexpr (std::is_same_v<Listing, NarListing>) {
to_json(j["entries"][name], child);
} else if constexpr (std::is_same_v<Listing, ShallowNarListing>) {
j["entries"][name] = nlohmann::json::object();
} else {
static_assert(false);
}
}
},
[&](const typename Listing::Symlink & s) {
j = nlohmann::json::object();
j["type"] = "symlink";
j["target"] = s.target;
},
},
listing.raw);
}
void to_json(nlohmann::json & j, const NarListing & listing)
{
to_json_impl(j, listing);
}
void to_json(nlohmann::json & j, const ShallowNarListing & listing)
{
to_json_impl(j, listing);
}
} // namespace nix