nix-eval-jobs/src/drv.cc
Pierre Bourdon d9a46559a4
drv: backport CA derivations support changes from hydra-eval-jobs
It is not possible to query output paths for CA derivations since
they're not static / known at eval time. Instead, return JSON nulls for
outputs paths.

This is a partial port of the following Hydra commits:

- 9ba4417940ffdd0fadea43f68c61ef948a4b8d39
- 069b7775c565f5999fe33e8c3f28c7b9306039ca
- fcde5908d8e51f975b883329b34d24a9f30ea4b3

By the following authors:

Co-Authored-By: John Ericson <John.Ericson@Obsidian.Systems>
Co-Authored-By: Théophane Hufschmitt <theophane.hufschmitt@tweag.io>
Co-Authored-By: Alexander Sosedkin <monk@unboiled.info>
Co-Authored-By: Andrea Ciceri <andrea.ciceri@autistici.org>
Co-Authored-By: Charlotte 🦝 Delenk Mlotte@chir.rs>
Co-Authored-By: Sandro Jäckel <sandro.jaeckel@gmail.com>
2024-07-16 09:15:21 +02:00

134 lines
4.5 KiB
C++

#include <lix/config.h> // IWYU pragma: keep
#include <lix/libstore/path-with-outputs.hh>
#include <lix/libstore/store-api.hh>
#include <lix/libstore/local-fs-store.hh>
#include <lix/libexpr/value-to-json.hh>
#include <lix/libstore/derivations.hh>
#include <stdint.h>
#include <lix/libstore/derived-path-map.hh>
#include <lix/libexpr/eval.hh>
#include <lix/libexpr/get-drvs.hh>
#include <lix/libexpr/nixexpr.hh>
#include <nlohmann/detail/json_ref.hpp>
#include <lix/libstore/path.hh>
#include <lix/libutil/ref.hh>
#include <lix/libexpr/value/context.hh>
#include <exception>
#include <memory>
#include <sstream>
#include <utility>
#include <vector>
#include "drv.hh"
#include "eval-args.hh"
static bool
queryIsCached(nix::Store &store,
std::map<std::string, std::optional<std::string>> &outputs) {
uint64_t downloadSize, narSize;
nix::StorePathSet willBuild, willSubstitute, unknown;
std::vector<nix::StorePathWithOutputs> paths;
for (auto const &[key, val] : outputs) {
if (val) {
paths.push_back(followLinksToStorePathWithOutputs(store, *val));
}
}
store.queryMissing(toDerivedPaths(paths), willBuild, willSubstitute,
unknown, downloadSize, narSize);
return willBuild.empty() && unknown.empty();
}
/* The fields of a derivation that are printed in json form */
Drv::Drv(std::string &attrPath, nix::EvalState &state, nix::DrvInfo &drvInfo,
MyArgs &args) {
auto localStore = state.store.dynamic_pointer_cast<nix::LocalFSStore>();
try {
// CA derivations do not have static output paths, so we have to
// defensively not query output paths in case we encounter one.
for (auto &[outputName, optOutputPath] :
drvInfo.queryOutputs(!nix::experimentalFeatureSettings.isEnabled(
nix::Xp::CaDerivations))) {
if (optOutputPath) {
outputs[outputName] =
localStore->printStorePath(*optOutputPath);
} else {
assert(nix::experimentalFeatureSettings.isEnabled(
nix::Xp::CaDerivations));
outputs[outputName] = std::nullopt;
}
}
} catch (const std::exception &e) {
throw nix::EvalError(state,
"derivation '%s' does not have valid outputs: %s",
attrPath, e.what());
}
if (args.meta) {
nlohmann::json meta_;
for (auto &metaName : drvInfo.queryMetaNames()) {
nix::NixStringContext context;
std::stringstream ss;
auto metaValue = drvInfo.queryMeta(metaName);
// Skip non-serialisable types
// TODO: Fix serialisation of derivations to store paths
if (metaValue == 0) {
continue;
}
nix::printValueAsJSON(state, true, *metaValue, nix::noPos, ss,
context);
meta_[metaName] = nlohmann::json::parse(ss.str());
}
meta = meta_;
}
if (args.checkCacheStatus) {
cacheStatus = queryIsCached(*localStore, outputs)
? Drv::CacheStatus::Cached
: Drv::CacheStatus::Uncached;
} else {
cacheStatus = Drv::CacheStatus::Unknown;
}
drvPath = localStore->printStorePath(drvInfo.requireDrvPath());
auto drv = localStore->readDerivation(drvInfo.requireDrvPath());
for (const auto &[inputDrvPath, inputNode] : drv.inputDrvs.map) {
std::set<std::string> inputDrvOutputs;
for (auto &outputName : inputNode.value) {
inputDrvOutputs.insert(outputName);
}
inputDrvs[localStore->printStorePath(inputDrvPath)] = inputDrvOutputs;
}
name = drvInfo.queryName();
system = drv.platform;
}
void to_json(nlohmann::json &json, const Drv &drv) {
std::map<std::string, nlohmann::json> outputsJson;
for (auto &[name, optPath] : drv.outputs) {
outputsJson[name] =
optPath ? nlohmann::json(*optPath) : nlohmann::json(nullptr);
}
json = nlohmann::json{{"name", drv.name},
{"system", drv.system},
{"drvPath", drv.drvPath},
{"outputs", outputsJson},
{"inputDrvs", drv.inputDrvs}};
if (drv.meta.has_value()) {
json["meta"] = drv.meta.value();
}
if (drv.cacheStatus != Drv::CacheStatus::Unknown) {
json["isCached"] = drv.cacheStatus == Drv::CacheStatus::Cached;
}
}