diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index cf18724ef..e05644ab2 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -5,6 +5,7 @@ #include "worker-protocol.hh" #include "fs-accessor.hh" #include +#include namespace nix { @@ -890,4 +891,62 @@ std::optional Derivation::tryResolve( const Hash impureOutputHash = hashString(htSHA256, "impure"); +nlohmann::json DerivationOutput::toJSON( + const Store & store, std::string_view drvName, std::string_view outputName) const +{ + nlohmann::json res = nlohmann::json::object(); + std::visit(overloaded { + [&](const DerivationOutput::InputAddressed & doi) { + res["path"] = store.printStorePath(doi.path); + }, + [&](const DerivationOutput::CAFixed & dof) { + res["path"] = store.printStorePath(dof.path(store, drvName, outputName)); + res["hashAlgo"] = dof.hash.printMethodAlgo(); + res["hash"] = dof.hash.hash.to_string(Base16, false); + }, + [&](const DerivationOutput::CAFloating & dof) { + res["hashAlgo"] = makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType); + }, + [&](const DerivationOutput::Deferred &) {}, + [&](const DerivationOutput::Impure & doi) { + res["hashAlgo"] = makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType); + res["impure"] = true; + }, + }, raw()); + return res; +} + +nlohmann::json Derivation::toJSON(const Store & store) const +{ + nlohmann::json res = nlohmann::json::object(); + + { + nlohmann::json & outputsObj = res["outputs"]; + outputsObj = nlohmann::json::object(); + for (auto & [outputName, output] : outputs) { + outputsObj[outputName] = output.toJSON(store, name, outputName); + } + } + + { + auto& inputsList = res["inputSrcs"]; + inputsList = nlohmann::json ::array(); + for (auto & input : inputSrcs) + inputsList.emplace_back(store.printStorePath(input)); + } + + { + auto& inputDrvsObj = res["inputDrvs"]; + inputDrvsObj = nlohmann::json ::object(); + for (auto & input : inputDrvs) + inputDrvsObj[store.printStorePath(input.first)] = input.second; + } + + res["system"] = platform; + res["builder"] = builder; + res["args"] = args; + + return res; +} + } diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh index f42c13cdc..8456b29e7 100644 --- a/src/libstore/derivations.hh +++ b/src/libstore/derivations.hh @@ -83,6 +83,11 @@ struct DerivationOutput : _DerivationOutputRaw inline const Raw & raw() const { return static_cast(*this); } + + nlohmann::json toJSON( + const Store & store, + std::string_view drvName, + std::string_view outputName) const; }; typedef std::map DerivationOutputs; @@ -210,6 +215,8 @@ struct Derivation : BasicDerivation Derivation() = default; Derivation(const BasicDerivation & bd) : BasicDerivation(bd) { } Derivation(BasicDerivation && bd) : BasicDerivation(std::move(bd)) { } + + nlohmann::json toJSON(const Store & store) const; }; diff --git a/src/libstore/tests/derivation.cc b/src/libstore/tests/derivation.cc new file mode 100644 index 000000000..c9d404188 --- /dev/null +++ b/src/libstore/tests/derivation.cc @@ -0,0 +1,115 @@ +#include +#include + +#include "derivations.hh" + +#include "tests/libstore.hh" + +namespace nix { + +class DerivationTest : public LibStoreTest +{ +}; + +#define TEST_JSON(TYPE, NAME, STR, VAL, ...) \ + TEST_F(DerivationTest, TYPE ## _ ## NAME ## _to_json) { \ + using nlohmann::literals::operator "" _json; \ + ASSERT_EQ( \ + STR ## _json, \ + (TYPE { VAL }).toJSON(*store __VA_OPT__(,) __VA_ARGS__)); \ + } + +TEST_JSON(DerivationOutput, inputAddressed, + R"({ + "path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name" + })", + (DerivationOutput::InputAddressed { + .path = store->parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"), + }), + "drv-name", "output-name") + +TEST_JSON(DerivationOutput, caFixed, + R"({ + "hashAlgo": "r:sha256", + "hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f", + "path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name" + })", + (DerivationOutput::CAFixed { + .hash = { + .method = FileIngestionMethod::Recursive, + .hash = Hash::parseAnyPrefixed("sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8="), + }, + }), + "drv-name", "output-name") + +TEST_JSON(DerivationOutput, caFloating, + R"({ + "hashAlgo": "r:sha256" + })", + (DerivationOutput::CAFloating { + .method = FileIngestionMethod::Recursive, + .hashType = htSHA256, + }), + "drv-name", "output-name") + +TEST_JSON(DerivationOutput, deferred, + R"({ })", + DerivationOutput::Deferred { }, + "drv-name", "output-name") + +TEST_JSON(DerivationOutput, impure, + R"({ + "hashAlgo": "r:sha256", + "impure": true + })", + (DerivationOutput::Impure { + .method = FileIngestionMethod::Recursive, + .hashType = htSHA256, + }), + "drv-name", "output-name") + +TEST_JSON(Derivation, impure, + R"({ + "inputSrcs": [ + "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1" + ], + "inputDrvs": { + "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": [ + "cat", + "dog" + ] + }, + "system": "wasm-sel4", + "builder": "foo", + "args": [ + "bar", + "baz" + ], + "outputs": {} + })", + ({ + Derivation drv; + drv.inputSrcs = { + store->parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"), + }; + drv.inputDrvs = { + { + store->parseStorePath("/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv"), + { + "cat", + "dog", + }, + } + }; + drv.platform = "wasm-sel4"; + drv.builder = "foo"; + drv.args = { + "bar", + "baz", + }; + drv; + })) + +#undef TEST_JSON + +} diff --git a/src/nix/show-derivation.cc b/src/nix/show-derivation.cc index af2e676a4..d1a516cad 100644 --- a/src/nix/show-derivation.cc +++ b/src/nix/show-derivation.cc @@ -54,56 +54,8 @@ struct CmdShowDerivation : InstallablesCommand for (auto & drvPath : drvPaths) { if (!drvPath.isDerivation()) continue; - json& drvObj = jsonRoot[store->printStorePath(drvPath)]; - - auto drv = store->readDerivation(drvPath); - - { - json& outputsObj = drvObj["outputs"]; - outputsObj = json::object(); - for (auto & [_outputName, output] : drv.outputs) { - auto & outputName = _outputName; // work around clang bug - auto& outputObj = outputsObj[outputName]; - outputObj = json::object(); - std::visit(overloaded { - [&](const DerivationOutput::InputAddressed & doi) { - outputObj["path"] = store->printStorePath(doi.path); - }, - [&](const DerivationOutput::CAFixed & dof) { - outputObj["path"] = store->printStorePath(dof.path(*store, drv.name, outputName)); - outputObj["hashAlgo"] = dof.hash.printMethodAlgo(); - outputObj["hash"] = dof.hash.hash.to_string(Base16, false); - }, - [&](const DerivationOutput::CAFloating & dof) { - outputObj["hashAlgo"] = makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType); - }, - [&](const DerivationOutput::Deferred &) {}, - [&](const DerivationOutput::Impure & doi) { - outputObj["hashAlgo"] = makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType); - outputObj["impure"] = true; - }, - }, output.raw()); - } - } - - { - auto& inputsList = drvObj["inputSrcs"]; - inputsList = json::array(); - for (auto & input : drv.inputSrcs) - inputsList.emplace_back(store->printStorePath(input)); - } - - { - auto& inputDrvsObj = drvObj["inputDrvs"]; - inputDrvsObj = json::object(); - for (auto & input : drv.inputDrvs) - inputDrvsObj[store->printStorePath(input.first)] = input.second; - } - - drvObj["system"] = drv.platform; - drvObj["builder"] = drv.builder; - drvObj["args"] = drv.args; - drvObj["env"] = drv.env; + jsonRoot[store->printStorePath(drvPath)] = + store->readDerivation(drvPath).toJSON(*store); } std::cout << jsonRoot.dump(2) << std::endl; }