1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-07-06 09:11:47 +02:00

Improve checked json casting (#10087)

This introduces new utility functions to get elements from JSON — in an ergonomic way and with nice error messages if the expected type does not match.

Co-authored-by: John Ericson <John.Ericson@Obsidian.Systems>
This commit is contained in:
HaeNoe 2024-04-03 20:04:00 +02:00 committed by GitHub
parent bf86b939f8
commit 50cb14fcf9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 315 additions and 69 deletions

View file

@ -1239,16 +1239,14 @@ DerivationOutput DerivationOutput::fromJSON(
const ExperimentalFeatureSettings & xpSettings)
{
std::set<std::string_view> keys;
ensureType(_json, nlohmann::detail::value_t::object);
auto json = (std::map<std::string, nlohmann::json>) _json;
auto & json = getObject(_json);
for (const auto & [key, _] : json)
keys.insert(key);
auto methodAlgo = [&]() -> std::pair<ContentAddressMethod, HashAlgorithm> {
std::string hashAlgoStr = json["hashAlgo"];
// remaining to parse, will be mutated by parsers
std::string_view s = hashAlgoStr;
auto & str = getString(valueAt(json, "hashAlgo"));
std::string_view s = str;
ContentAddressMethod method = ContentAddressMethod::parsePrefix(s);
if (method == TextIngestionMethod {})
xpSettings.require(Xp::DynamicDerivations);
@ -1258,7 +1256,7 @@ DerivationOutput DerivationOutput::fromJSON(
if (keys == (std::set<std::string_view> { "path" })) {
return DerivationOutput::InputAddressed {
.path = store.parseStorePath((std::string) json["path"]),
.path = store.parseStorePath(getString(valueAt(json, "path"))),
};
}
@ -1267,10 +1265,10 @@ DerivationOutput DerivationOutput::fromJSON(
auto dof = DerivationOutput::CAFixed {
.ca = ContentAddress {
.method = std::move(method),
.hash = Hash::parseNonSRIUnprefixed((std::string) json["hash"], hashAlgo),
.hash = Hash::parseNonSRIUnprefixed(getString(valueAt(json, "hash")), hashAlgo),
},
};
if (dof.path(store, drvName, outputName) != store.parseStorePath((std::string) json["path"]))
if (dof.path(store, drvName, outputName) != store.parseStorePath(getString(valueAt(json, "path"))))
throw Error("Path doesn't match derivation output");
return dof;
}
@ -1357,20 +1355,19 @@ nlohmann::json Derivation::toJSON(const StoreDirConfig & store) const
Derivation Derivation::fromJSON(
const StoreDirConfig & store,
const nlohmann::json & json,
const nlohmann::json & _json,
const ExperimentalFeatureSettings & xpSettings)
{
using nlohmann::detail::value_t;
Derivation res;
ensureType(json, value_t::object);
auto & json = getObject(_json);
res.name = ensureType(valueAt(json, "name"), value_t::string);
res.name = getString(valueAt(json, "name"));
try {
auto & outputsObj = ensureType(valueAt(json, "outputs"), value_t::object);
for (auto & [outputName, output] : outputsObj.items()) {
for (auto & [outputName, output] : getObject(valueAt(json, "outputs"))) {
res.outputs.insert_or_assign(
outputName,
DerivationOutput::fromJSON(store, res.name, outputName, output));
@ -1381,8 +1378,7 @@ Derivation Derivation::fromJSON(
}
try {
auto & inputsList = ensureType(valueAt(json, "inputSrcs"), value_t::array);
for (auto & input : inputsList)
for (auto & input : getArray(valueAt(json, "inputSrcs")))
res.inputSrcs.insert(store.parseStorePath(static_cast<const std::string &>(input)));
} catch (Error & e) {
e.addTrace({}, "while reading key 'inputSrcs'");
@ -1391,18 +1387,17 @@ Derivation Derivation::fromJSON(
try {
std::function<DerivedPathMap<StringSet>::ChildNode(const nlohmann::json &)> doInput;
doInput = [&](const auto & json) {
doInput = [&](const auto & _json) {
auto & json = getObject(_json);
DerivedPathMap<StringSet>::ChildNode node;
node.value = static_cast<const StringSet &>(
ensureType(valueAt(json, "outputs"), value_t::array));
for (auto & [outputId, childNode] : ensureType(valueAt(json, "dynamicOutputs"), value_t::object).items()) {
node.value = getStringSet(valueAt(json, "outputs"));
for (auto & [outputId, childNode] : getObject(valueAt(json, "dynamicOutputs"))) {
xpSettings.require(Xp::DynamicDerivations);
node.childMap[outputId] = doInput(childNode);
}
return node;
};
auto & inputDrvsObj = ensureType(valueAt(json, "inputDrvs"), value_t::object);
for (auto & [inputDrvPath, inputOutputs] : inputDrvsObj.items())
for (auto & [inputDrvPath, inputOutputs] : getObject(valueAt(json, "inputDrvs")))
res.inputDrvs.map[store.parseStorePath(inputDrvPath)] =
doInput(inputOutputs);
} catch (Error & e) {
@ -1410,10 +1405,10 @@ Derivation Derivation::fromJSON(
throw;
}
res.platform = ensureType(valueAt(json, "system"), value_t::string);
res.builder = ensureType(valueAt(json, "builder"), value_t::string);
res.args = ensureType(valueAt(json, "args"), value_t::array);
res.env = ensureType(valueAt(json, "env"), value_t::object);
res.platform = getString(valueAt(json, "system"));
res.builder = getString(valueAt(json, "builder"));
res.args = getStringList(valueAt(json, "args"));
res.env = getStringMap(valueAt(json, "env"));
return res;
}