diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index 76539e95131..8ce2ef30a32 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -1425,12 +1425,8 @@ void adl_serializer::to_json(json & res, const DerivationOutpu DerivationOutput adl_serializer::from_json(const json & _json, const ExperimentalFeatureSettings & xpSettings) { - std::set keys; auto & json = getObject(_json); - for (const auto & [key, _] : json) - keys.insert(key); - auto methodAlgo = [&]() -> std::pair { ContentAddressMethod method = ContentAddressMethod::parse(getString(valueAt(json, "method"))); if (method == ContentAddressMethod::Raw::Text) @@ -1440,52 +1436,57 @@ adl_serializer::from_json(const json & _json, const Experiment return {std::move(method), std::move(hashAlgo)}; }; - if (keys == (std::set{"path"})) { - return DerivationOutput::InputAddressed{ - .path = valueAt(json, "path"), - }; - } + switch (json.size()) { + case 0: + return DerivationOutput::Deferred{}; + case 1: + if (auto * path = optionalValueAt(json, "path")) + return DerivationOutput::InputAddressed{ + .path = *path, + }; + break; + case 2: { + const bool hasMethod = optionalValueAt(json, "method"); - else if (keys == (std::set{"method", "hash"})) { - auto dof = DerivationOutput::CAFixed{ - .ca = static_cast(_json), - }; - if (dof.ca.method == ContentAddressMethod::Raw::Text) - xpSettings.require(Xp::DynamicDerivations, "text-hashed derivation output in JSON"); - /* We no longer produce this (denormalized) field (for the - reasons described above), so we don't need to check it. */ + if (hasMethod && optionalValueAt(json, "hash")) { + auto dof = DerivationOutput::CAFixed{ + .ca = static_cast(_json), + }; + if (dof.ca.method == ContentAddressMethod::Raw::Text) + xpSettings.require(Xp::DynamicDerivations, "text-hashed derivation output in JSON"); + /* We no longer produce this (denormalized) field (for the + reasons described above), so we don't need to check it. */ #if 0 - if (dof.path(store, drvName, outputName) != static_cast(valueAt(json, "path"))) - throw Error("Path doesn't match derivation output"); + if (dof.path(store, drvName, outputName) != static_cast(valueAt(json, "path"))) + throw Error("Path doesn't match derivation output"); #endif - return dof; - } + return dof; + } - else if (keys == (std::set{"method", "hashAlgo"})) { - xpSettings.require(Xp::CaDerivations); - auto [method, hashAlgo] = methodAlgo(); - return DerivationOutput::CAFloating{ - .method = std::move(method), - .hashAlgo = std::move(hashAlgo), - }; - } + if (hasMethod && optionalValueAt(json, "hashAlgo")) { + xpSettings.require(Xp::CaDerivations); + auto [method, hashAlgo] = methodAlgo(); + return DerivationOutput::CAFloating{ + .method = std::move(method), + .hashAlgo = std::move(hashAlgo), + }; + } - else if (keys == (std::set{})) { - return DerivationOutput::Deferred{}; + break; } - - else if (keys == (std::set{"method", "hashAlgo", "impure"})) { - xpSettings.require(Xp::ImpureDerivations); - auto [method, hashAlgo] = methodAlgo(); - return DerivationOutput::Impure{ - .method = std::move(method), - .hashAlgo = hashAlgo, - }; + case 3: + if (optionalValueAt(json, "method") && optionalValueAt(json, "hashAlgo") && optionalValueAt(json, "impure")) { + xpSettings.require(Xp::ImpureDerivations); + auto [method, hashAlgo] = methodAlgo(); + return DerivationOutput::Impure{ + .method = std::move(method), + .hashAlgo = hashAlgo, + }; + } + break; } - else { - throw Error("invalid JSON for derivation output"); - } + throw Error("invalid JSON for derivation output"); } void adl_serializer::to_json(json & res, const Derivation & d)