1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-09 20:16:03 +01:00

Merge pull request #14012 from obsidiansystems/drv-realisation-issue-13570

Convert Realisation JSON logic to standard style
This commit is contained in:
Robert Hensing 2025-09-22 20:25:06 +02:00 committed by GitHub
commit 01357d0808
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 81 additions and 71 deletions

View file

@ -4,14 +4,12 @@ prs: [13980]
issues: [13570] issues: [13570]
--- ---
Experience with many JSON frameworks (e.g. nlohmann/json in C++, Serde Experience with many JSON frameworks (e.g. nlohmann/json in C++, Serde in Rust, and Aeson in Haskell), has shown that the use of the store dir in JSON formats is an impediment to systematic JSON formats,
in Rust, and Aeson in Haskell), has show that the use of the store dir because it requires the serializer/deserializer to take an extra paramater (the store dir).
in JSON formats is an impediment to systematic JSON formats, because it
requires the serializer/deserializer to take an extra paramater (the
store dir).
We ultimately want to rectify this issue with all (non-stable, able to We ultimately want to rectify this issue with all (non-stable, able to be changed) JSON formats.
be changed) JSON formats. To start with, we are changing the JSON format To start with, we are changing the JSON format for derivations because the `nix derivation` commands are
for derivations because the `nix derivation` commands are --- in --- in addition to being formally unstable
addition to being formally unstable --- less widely used than other --- less widely used than other unstable commands.
unstable commands.
See the documentation on the [JSON format for derivations](@docroot@/protocols/json/derivation.md) for further details.

View file

@ -515,8 +515,14 @@ void BinaryCacheStore::queryRealisationUncached(
if (!data) if (!data)
return (*callbackPtr)({}); return (*callbackPtr)({});
auto realisation = Realisation::fromJSON(nlohmann::json::parse(*data), outputInfoFilePath); std::shared_ptr<const Realisation> realisation;
return (*callbackPtr)(std::make_shared<const Realisation>(realisation)); try {
realisation = std::make_shared<const Realisation>(nlohmann::json::parse(*data));
} catch (Error & e) {
e.addTrace({}, "while parsing file '%s' as a realisation", outputInfoFilePath);
throw;
}
return (*callbackPtr)(std::move(realisation));
} catch (...) { } catch (...) {
callbackPtr->rethrow(); callbackPtr->rethrow();
} }
@ -530,7 +536,7 @@ void BinaryCacheStore::registerDrvOutput(const Realisation & info)
if (diskCache) if (diskCache)
diskCache->upsertRealisation(config.getReference().render(/*FIXME withParams=*/false), info); diskCache->upsertRealisation(config.getReference().render(/*FIXME withParams=*/false), info);
auto filePath = realisationsPrefix + "/" + info.id.to_string() + ".doi"; auto filePath = realisationsPrefix + "/" + info.id.to_string() + ".doi";
upsertFile(filePath, info.toJSON().dump(), "application/json"); upsertFile(filePath, static_cast<nlohmann::json>(info).dump(), "application/json");
} }
ref<SourceAccessor> BinaryCacheStore::getFSAccessor(bool requireValidPath) ref<SourceAccessor> BinaryCacheStore::getFSAccessor(bool requireValidPath)

View file

@ -49,13 +49,18 @@ void CommonProto::Serialise<ContentAddress>::write(
Realisation CommonProto::Serialise<Realisation>::read(const StoreDirConfig & store, CommonProto::ReadConn conn) Realisation CommonProto::Serialise<Realisation>::read(const StoreDirConfig & store, CommonProto::ReadConn conn)
{ {
std::string rawInput = readString(conn.from); std::string rawInput = readString(conn.from);
return Realisation::fromJSON(nlohmann::json::parse(rawInput), "remote-protocol"); try {
return nlohmann::json::parse(rawInput);
} catch (Error & e) {
e.addTrace({}, "while parsing a realisation object in the remote protocol");
throw;
}
} }
void CommonProto::Serialise<Realisation>::write( void CommonProto::Serialise<Realisation>::write(
const StoreDirConfig & store, CommonProto::WriteConn conn, const Realisation & realisation) const StoreDirConfig & store, CommonProto::WriteConn conn, const Realisation & realisation)
{ {
conn.to << realisation.toJSON().dump(); conn.to << static_cast<nlohmann::json>(realisation).dump();
} }
DrvOutput CommonProto::Serialise<DrvOutput>::read(const StoreDirConfig & store, CommonProto::ReadConn conn) DrvOutput CommonProto::Serialise<DrvOutput>::read(const StoreDirConfig & store, CommonProto::ReadConn conn)

View file

@ -64,9 +64,6 @@ struct Realisation
*/ */
std::map<DrvOutput, StorePath> dependentRealisations; std::map<DrvOutput, StorePath> dependentRealisations;
nlohmann::json toJSON() const;
static Realisation fromJSON(const nlohmann::json & json, const std::string & whence);
std::string fingerprint() const; std::string fingerprint() const;
void sign(const Signer &); void sign(const Signer &);
bool checkSignature(const PublicKeys & publicKeys, const std::string & sig) const; bool checkSignature(const PublicKeys & publicKeys, const std::string & sig) const;
@ -169,3 +166,5 @@ public:
}; };
} // namespace nix } // namespace nix
JSON_IMPL(nix::Realisation)

View file

@ -304,10 +304,15 @@ public:
if (queryRealisation.isNull(0)) if (queryRealisation.isNull(0))
return {oInvalid, 0}; return {oInvalid, 0};
auto realisation = std::make_shared<Realisation>( try {
Realisation::fromJSON(nlohmann::json::parse(queryRealisation.getStr(0)), "Local disk cache")); return {
oValid,
return {oValid, realisation}; std::make_shared<Realisation>(nlohmann::json::parse(queryRealisation.getStr(0))),
};
} catch (Error & e) {
e.addTrace({}, "while parsing the local disk cache");
throw;
}
}); });
} }
@ -349,7 +354,8 @@ public:
auto & cache(getCache(*state, uri)); auto & cache(getCache(*state, uri));
state->insertRealisation.use()(cache.id)(realisation.id.to_string())(realisation.toJSON().dump())(time(0)) state->insertRealisation
.use()(cache.id)(realisation.id.to_string())(static_cast<nlohmann::json>(realisation).dump())(time(0))
.exec(); .exec();
}); });
} }

View file

@ -2,6 +2,7 @@
#include "nix/store/store-api.hh" #include "nix/store/store-api.hh"
#include "nix/util/closure.hh" #include "nix/util/closure.hh"
#include "nix/util/signature/local-keys.hh" #include "nix/util/signature/local-keys.hh"
#include "nix/util/json-utils.hh"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
namespace nix { namespace nix {
@ -60,54 +61,9 @@ void Realisation::closure(Store & store, const std::set<Realisation> & startOutp
}); });
} }
nlohmann::json Realisation::toJSON() const
{
auto jsonDependentRealisations = nlohmann::json::object();
for (auto & [depId, depOutPath] : dependentRealisations)
jsonDependentRealisations.emplace(depId.to_string(), depOutPath.to_string());
return nlohmann::json{
{"id", id.to_string()},
{"outPath", outPath.to_string()},
{"signatures", signatures},
{"dependentRealisations", jsonDependentRealisations},
};
}
Realisation Realisation::fromJSON(const nlohmann::json & json, const std::string & whence)
{
auto getOptionalField = [&](std::string fieldName) -> std::optional<std::string> {
auto fieldIterator = json.find(fieldName);
if (fieldIterator == json.end())
return std::nullopt;
return {*fieldIterator};
};
auto getField = [&](std::string fieldName) -> std::string {
if (auto field = getOptionalField(fieldName))
return *field;
else
throw Error("Drv output info file '%1%' is corrupt, missing field %2%", whence, fieldName);
};
StringSet signatures;
if (auto signaturesIterator = json.find("signatures"); signaturesIterator != json.end())
signatures.insert(signaturesIterator->begin(), signaturesIterator->end());
std::map<DrvOutput, StorePath> dependentRealisations;
if (auto jsonDependencies = json.find("dependentRealisations"); jsonDependencies != json.end())
for (auto & [jsonDepId, jsonDepOutPath] : jsonDependencies->get<StringMap>())
dependentRealisations.insert({DrvOutput::parse(jsonDepId), StorePath(jsonDepOutPath)});
return Realisation{
.id = DrvOutput::parse(getField("id")),
.outPath = StorePath(getField("outPath")),
.signatures = signatures,
.dependentRealisations = dependentRealisations,
};
}
std::string Realisation::fingerprint() const std::string Realisation::fingerprint() const
{ {
auto serialized = toJSON(); nlohmann::json serialized = *this;
serialized.erase("signatures"); serialized.erase("signatures");
return serialized.dump(); return serialized.dump();
} }
@ -183,3 +139,43 @@ RealisedPath::Set RealisedPath::closure(Store & store) const
} }
} // namespace nix } // namespace nix
namespace nlohmann {
using namespace nix;
Realisation adl_serializer<Realisation>::from_json(const json & json0)
{
auto json = getObject(json0);
StringSet signatures;
if (auto signaturesOpt = optionalValueAt(json, "signatures"))
signatures = *signaturesOpt;
std::map<DrvOutput, StorePath> dependentRealisations;
if (auto jsonDependencies = optionalValueAt(json, "dependentRealisations"))
for (auto & [jsonDepId, jsonDepOutPath] : getObject(*jsonDependencies))
dependentRealisations.insert({DrvOutput::parse(jsonDepId), jsonDepOutPath});
return Realisation{
.id = DrvOutput::parse(valueAt(json, "id")),
.outPath = valueAt(json, "outPath"),
.signatures = signatures,
.dependentRealisations = dependentRealisations,
};
}
void adl_serializer<Realisation>::to_json(json & json, Realisation r)
{
auto jsonDependentRealisations = nlohmann::json::object();
for (auto & [depId, depOutPath] : r.dependentRealisations)
jsonDependentRealisations.emplace(depId.to_string(), depOutPath);
json = {
{"id", r.id.to_string()},
{"outPath", r.outPath},
{"signatures", r.signatures},
{"dependentRealisations", jsonDependentRealisations},
};
}
} // namespace nlohmann

View file

@ -59,7 +59,7 @@ struct CmdRealisationInfo : BuiltPathsCommand, MixJSON
for (auto & path : realisations) { for (auto & path : realisations) {
nlohmann::json currentPath; nlohmann::json currentPath;
if (auto realisation = std::get_if<Realisation>(&path.raw)) if (auto realisation = std::get_if<Realisation>(&path.raw))
currentPath = realisation->toJSON(); currentPath = *realisation;
else else
currentPath["opaquePath"] = store->printStorePath(path.path()); currentPath["opaquePath"] = store->printStorePath(path.path());

View file

@ -168,7 +168,7 @@ StoreWrapper::queryRawRealisation(char * outputId)
try { try {
auto realisation = THIS->store->queryRealisation(DrvOutput::parse(outputId)); auto realisation = THIS->store->queryRealisation(DrvOutput::parse(outputId));
if (realisation) if (realisation)
XPUSHs(sv_2mortal(newSVpv(realisation->toJSON().dump().c_str(), 0))); XPUSHs(sv_2mortal(newSVpv(static_cast<nlohmann::json>(*realisation).dump().c_str(), 0)));
else else
XPUSHs(sv_2mortal(newSVpv("", 0))); XPUSHs(sv_2mortal(newSVpv("", 0)));
} catch (Error & e) { } catch (Error & e) {