Skip to content

Commit 01357d0

Browse files
authored
Merge pull request #14012 from obsidiansystems/drv-realisation-issue-13570
Convert Realisation JSON logic to standard style
2 parents 169a368 + 91593a2 commit 01357d0

File tree

8 files changed

+81
-71
lines changed

8 files changed

+81
-71
lines changed

doc/manual/rl-next/derivation-json.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ prs: [13980]
44
issues: [13570]
55
---
66

7-
Experience with many JSON frameworks (e.g. nlohmann/json in C++, Serde
8-
in Rust, and Aeson in Haskell), has show that the use of the store dir
9-
in JSON formats is an impediment to systematic JSON formats, because it
10-
requires the serializer/deserializer to take an extra paramater (the
11-
store dir).
7+
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,
8+
because it requires the serializer/deserializer to take an extra paramater (the store dir).
129

13-
We ultimately want to rectify this issue with all (non-stable, able to
14-
be changed) JSON formats. To start with, we are changing the JSON format
15-
for derivations because the `nix derivation` commands are --- in
16-
addition to being formally unstable --- less widely used than other
17-
unstable commands.
10+
We ultimately want to rectify this issue with all (non-stable, able to be changed) JSON formats.
11+
To start with, we are changing the JSON format for derivations because the `nix derivation` commands are
12+
--- in addition to being formally unstable
13+
--- less widely used than other unstable commands.
14+
15+
See the documentation on the [JSON format for derivations](@docroot@/protocols/json/derivation.md) for further details.

src/libstore/binary-cache-store.cc

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -515,8 +515,14 @@ void BinaryCacheStore::queryRealisationUncached(
515515
if (!data)
516516
return (*callbackPtr)({});
517517

518-
auto realisation = Realisation::fromJSON(nlohmann::json::parse(*data), outputInfoFilePath);
519-
return (*callbackPtr)(std::make_shared<const Realisation>(realisation));
518+
std::shared_ptr<const Realisation> realisation;
519+
try {
520+
realisation = std::make_shared<const Realisation>(nlohmann::json::parse(*data));
521+
} catch (Error & e) {
522+
e.addTrace({}, "while parsing file '%s' as a realisation", outputInfoFilePath);
523+
throw;
524+
}
525+
return (*callbackPtr)(std::move(realisation));
520526
} catch (...) {
521527
callbackPtr->rethrow();
522528
}
@@ -530,7 +536,7 @@ void BinaryCacheStore::registerDrvOutput(const Realisation & info)
530536
if (diskCache)
531537
diskCache->upsertRealisation(config.getReference().render(/*FIXME withParams=*/false), info);
532538
auto filePath = realisationsPrefix + "/" + info.id.to_string() + ".doi";
533-
upsertFile(filePath, info.toJSON().dump(), "application/json");
539+
upsertFile(filePath, static_cast<nlohmann::json>(info).dump(), "application/json");
534540
}
535541

536542
ref<SourceAccessor> BinaryCacheStore::getFSAccessor(bool requireValidPath)

src/libstore/common-protocol.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,18 @@ void CommonProto::Serialise<ContentAddress>::write(
4949
Realisation CommonProto::Serialise<Realisation>::read(const StoreDirConfig & store, CommonProto::ReadConn conn)
5050
{
5151
std::string rawInput = readString(conn.from);
52-
return Realisation::fromJSON(nlohmann::json::parse(rawInput), "remote-protocol");
52+
try {
53+
return nlohmann::json::parse(rawInput);
54+
} catch (Error & e) {
55+
e.addTrace({}, "while parsing a realisation object in the remote protocol");
56+
throw;
57+
}
5358
}
5459

5560
void CommonProto::Serialise<Realisation>::write(
5661
const StoreDirConfig & store, CommonProto::WriteConn conn, const Realisation & realisation)
5762
{
58-
conn.to << realisation.toJSON().dump();
63+
conn.to << static_cast<nlohmann::json>(realisation).dump();
5964
}
6065

6166
DrvOutput CommonProto::Serialise<DrvOutput>::read(const StoreDirConfig & store, CommonProto::ReadConn conn)

src/libstore/include/nix/store/realisation.hh

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,6 @@ struct Realisation
6464
*/
6565
std::map<DrvOutput, StorePath> dependentRealisations;
6666

67-
nlohmann::json toJSON() const;
68-
static Realisation fromJSON(const nlohmann::json & json, const std::string & whence);
69-
7067
std::string fingerprint() const;
7168
void sign(const Signer &);
7269
bool checkSignature(const PublicKeys & publicKeys, const std::string & sig) const;
@@ -169,3 +166,5 @@ public:
169166
};
170167

171168
} // namespace nix
169+
170+
JSON_IMPL(nix::Realisation)

src/libstore/nar-info-disk-cache.cc

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,15 @@ class NarInfoDiskCacheImpl : public NarInfoDiskCache
304304
if (queryRealisation.isNull(0))
305305
return {oInvalid, 0};
306306

307-
auto realisation = std::make_shared<Realisation>(
308-
Realisation::fromJSON(nlohmann::json::parse(queryRealisation.getStr(0)), "Local disk cache"));
309-
310-
return {oValid, realisation};
307+
try {
308+
return {
309+
oValid,
310+
std::make_shared<Realisation>(nlohmann::json::parse(queryRealisation.getStr(0))),
311+
};
312+
} catch (Error & e) {
313+
e.addTrace({}, "while parsing the local disk cache");
314+
throw;
315+
}
311316
});
312317
}
313318

@@ -349,7 +354,8 @@ class NarInfoDiskCacheImpl : public NarInfoDiskCache
349354

350355
auto & cache(getCache(*state, uri));
351356

352-
state->insertRealisation.use()(cache.id)(realisation.id.to_string())(realisation.toJSON().dump())(time(0))
357+
state->insertRealisation
358+
.use()(cache.id)(realisation.id.to_string())(static_cast<nlohmann::json>(realisation).dump())(time(0))
353359
.exec();
354360
});
355361
}

src/libstore/realisation.cc

Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "nix/store/store-api.hh"
33
#include "nix/util/closure.hh"
44
#include "nix/util/signature/local-keys.hh"
5+
#include "nix/util/json-utils.hh"
56
#include <nlohmann/json.hpp>
67

78
namespace nix {
@@ -60,54 +61,9 @@ void Realisation::closure(Store & store, const std::set<Realisation> & startOutp
6061
});
6162
}
6263

63-
nlohmann::json Realisation::toJSON() const
64-
{
65-
auto jsonDependentRealisations = nlohmann::json::object();
66-
for (auto & [depId, depOutPath] : dependentRealisations)
67-
jsonDependentRealisations.emplace(depId.to_string(), depOutPath.to_string());
68-
return nlohmann::json{
69-
{"id", id.to_string()},
70-
{"outPath", outPath.to_string()},
71-
{"signatures", signatures},
72-
{"dependentRealisations", jsonDependentRealisations},
73-
};
74-
}
75-
76-
Realisation Realisation::fromJSON(const nlohmann::json & json, const std::string & whence)
77-
{
78-
auto getOptionalField = [&](std::string fieldName) -> std::optional<std::string> {
79-
auto fieldIterator = json.find(fieldName);
80-
if (fieldIterator == json.end())
81-
return std::nullopt;
82-
return {*fieldIterator};
83-
};
84-
auto getField = [&](std::string fieldName) -> std::string {
85-
if (auto field = getOptionalField(fieldName))
86-
return *field;
87-
else
88-
throw Error("Drv output info file '%1%' is corrupt, missing field %2%", whence, fieldName);
89-
};
90-
91-
StringSet signatures;
92-
if (auto signaturesIterator = json.find("signatures"); signaturesIterator != json.end())
93-
signatures.insert(signaturesIterator->begin(), signaturesIterator->end());
94-
95-
std::map<DrvOutput, StorePath> dependentRealisations;
96-
if (auto jsonDependencies = json.find("dependentRealisations"); jsonDependencies != json.end())
97-
for (auto & [jsonDepId, jsonDepOutPath] : jsonDependencies->get<StringMap>())
98-
dependentRealisations.insert({DrvOutput::parse(jsonDepId), StorePath(jsonDepOutPath)});
99-
100-
return Realisation{
101-
.id = DrvOutput::parse(getField("id")),
102-
.outPath = StorePath(getField("outPath")),
103-
.signatures = signatures,
104-
.dependentRealisations = dependentRealisations,
105-
};
106-
}
107-
10864
std::string Realisation::fingerprint() const
10965
{
110-
auto serialized = toJSON();
66+
nlohmann::json serialized = *this;
11167
serialized.erase("signatures");
11268
return serialized.dump();
11369
}
@@ -183,3 +139,43 @@ RealisedPath::Set RealisedPath::closure(Store & store) const
183139
}
184140

185141
} // namespace nix
142+
143+
namespace nlohmann {
144+
145+
using namespace nix;
146+
147+
Realisation adl_serializer<Realisation>::from_json(const json & json0)
148+
{
149+
auto json = getObject(json0);
150+
151+
StringSet signatures;
152+
if (auto signaturesOpt = optionalValueAt(json, "signatures"))
153+
signatures = *signaturesOpt;
154+
155+
std::map<DrvOutput, StorePath> dependentRealisations;
156+
if (auto jsonDependencies = optionalValueAt(json, "dependentRealisations"))
157+
for (auto & [jsonDepId, jsonDepOutPath] : getObject(*jsonDependencies))
158+
dependentRealisations.insert({DrvOutput::parse(jsonDepId), jsonDepOutPath});
159+
160+
return Realisation{
161+
.id = DrvOutput::parse(valueAt(json, "id")),
162+
.outPath = valueAt(json, "outPath"),
163+
.signatures = signatures,
164+
.dependentRealisations = dependentRealisations,
165+
};
166+
}
167+
168+
void adl_serializer<Realisation>::to_json(json & json, Realisation r)
169+
{
170+
auto jsonDependentRealisations = nlohmann::json::object();
171+
for (auto & [depId, depOutPath] : r.dependentRealisations)
172+
jsonDependentRealisations.emplace(depId.to_string(), depOutPath);
173+
json = {
174+
{"id", r.id.to_string()},
175+
{"outPath", r.outPath},
176+
{"signatures", r.signatures},
177+
{"dependentRealisations", jsonDependentRealisations},
178+
};
179+
}
180+
181+
} // namespace nlohmann

src/nix/realisation.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ struct CmdRealisationInfo : BuiltPathsCommand, MixJSON
5959
for (auto & path : realisations) {
6060
nlohmann::json currentPath;
6161
if (auto realisation = std::get_if<Realisation>(&path.raw))
62-
currentPath = realisation->toJSON();
62+
currentPath = *realisation;
6363
else
6464
currentPath["opaquePath"] = store->printStorePath(path.path());
6565

src/perl/lib/Nix/Store.xs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ StoreWrapper::queryRawRealisation(char * outputId)
168168
try {
169169
auto realisation = THIS->store->queryRealisation(DrvOutput::parse(outputId));
170170
if (realisation)
171-
XPUSHs(sv_2mortal(newSVpv(realisation->toJSON().dump().c_str(), 0)));
171+
XPUSHs(sv_2mortal(newSVpv(static_cast<nlohmann::json>(*realisation).dump().c_str(), 0)));
172172
else
173173
XPUSHs(sv_2mortal(newSVpv("", 0)));
174174
} catch (Error & e) {

0 commit comments

Comments
 (0)