1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-25 02:21:16 +02:00
nix/src/libstore/derivation-options.cc
John Ericson 29ae14114e Remove stray assignment side affect in lambda
This was almost a bug! It wasn't simply because another assignment would
clobber it later.

(cherry picked from commit 32409dd7d7)
2025-04-15 14:25:16 -04:00

273 lines
11 KiB
C++

#include "nix/store/derivation-options.hh"
#include "nix/util/json-utils.hh"
#include "nix/store/parsed-derivations.hh"
#include "nix/util/types.hh"
#include "nix/util/util.hh"
#include <optional>
#include <string>
#include <variant>
namespace nix {
using OutputChecks = DerivationOptions::OutputChecks;
using OutputChecksVariant = std::variant<OutputChecks, std::map<std::string, OutputChecks>>;
DerivationOptions DerivationOptions::fromParsedDerivation(const ParsedDerivation & parsed, bool shouldWarn)
{
DerivationOptions defaults = {};
auto structuredAttrs = parsed.structuredAttrs.get();
if (shouldWarn && structuredAttrs) {
if (get(*structuredAttrs, "allowedReferences")) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'allowedReferences'; use 'outputChecks' instead");
}
if (get(*structuredAttrs, "allowedRequisites")) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'allowedRequisites'; use 'outputChecks' instead");
}
if (get(*structuredAttrs, "disallowedRequisites")) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'disallowedRequisites'; use 'outputChecks' instead");
}
if (get(*structuredAttrs, "disallowedReferences")) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'disallowedReferences'; use 'outputChecks' instead");
}
if (get(*structuredAttrs, "maxSize")) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'maxSize'; use 'outputChecks' instead");
}
if (get(*structuredAttrs, "maxClosureSize")) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'maxClosureSize'; use 'outputChecks' instead");
}
}
return {
.outputChecks = [&]() -> OutputChecksVariant {
if (auto structuredAttrs = parsed.structuredAttrs.get()) {
std::map<std::string, OutputChecks> res;
if (auto outputChecks = get(*structuredAttrs, "outputChecks")) {
for (auto & [outputName, output] : getObject(*outputChecks)) {
OutputChecks checks;
if (auto maxSize = get(output, "maxSize"))
checks.maxSize = maxSize->get<uint64_t>();
if (auto maxClosureSize = get(output, "maxClosureSize"))
checks.maxClosureSize = maxClosureSize->get<uint64_t>();
auto get_ = [&](const std::string & name) -> std::optional<StringSet> {
if (auto i = get(output, name)) {
StringSet res;
for (auto j = i->begin(); j != i->end(); ++j) {
if (!j->is_string())
throw Error("attribute '%s' must be a list of strings", name);
res.insert(j->get<std::string>());
}
return res;
}
return {};
};
checks.allowedReferences = get_("allowedReferences");
checks.allowedRequisites = get_("allowedRequisites");
checks.disallowedReferences = get_("disallowedReferences").value_or(StringSet{});
checks.disallowedRequisites = get_("disallowedRequisites").value_or(StringSet{});
;
res.insert_or_assign(outputName, std::move(checks));
}
}
return res;
} else {
return OutputChecks{
// legacy non-structured-attributes case
.ignoreSelfRefs = true,
.allowedReferences = parsed.getStringSetAttr("allowedReferences"),
.disallowedReferences = parsed.getStringSetAttr("disallowedReferences").value_or(StringSet{}),
.allowedRequisites = parsed.getStringSetAttr("allowedRequisites"),
.disallowedRequisites = parsed.getStringSetAttr("disallowedRequisites").value_or(StringSet{}),
};
}
}(),
.unsafeDiscardReferences =
[&] {
std::map<std::string, bool> res;
if (auto structuredAttrs = parsed.structuredAttrs.get()) {
if (auto udr = get(*structuredAttrs, "unsafeDiscardReferences")) {
for (auto & [outputName, output] : getObject(*udr)) {
if (!output.is_boolean())
throw Error("attribute 'unsafeDiscardReferences.\"%s\"' must be a Boolean", outputName);
res.insert_or_assign(outputName, output.get<bool>());
}
}
}
return res;
}(),
.passAsFile =
[&] {
StringSet res;
if (auto * passAsFileString = get(parsed.drv.env, "passAsFile")) {
if (parsed.hasStructuredAttrs()) {
if (shouldWarn) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'passAsFile'; because all JSON is always passed via file");
}
} else {
res = tokenizeString<StringSet>(*passAsFileString);
}
}
return res;
}(),
.additionalSandboxProfile =
parsed.getStringAttr("__sandboxProfile").value_or(defaults.additionalSandboxProfile),
.noChroot = parsed.getBoolAttr("__noChroot", defaults.noChroot),
.impureHostDeps = parsed.getStringSetAttr("__impureHostDeps").value_or(defaults.impureHostDeps),
.impureEnvVars = parsed.getStringSetAttr("impureEnvVars").value_or(defaults.impureEnvVars),
.allowLocalNetworking = parsed.getBoolAttr("__darwinAllowLocalNetworking", defaults.allowLocalNetworking),
.requiredSystemFeatures =
parsed.getStringSetAttr("requiredSystemFeatures").value_or(defaults.requiredSystemFeatures),
.preferLocalBuild = parsed.getBoolAttr("preferLocalBuild", defaults.preferLocalBuild),
.allowSubstitutes = parsed.getBoolAttr("allowSubstitutes", defaults.allowSubstitutes),
};
}
StringSet DerivationOptions::getRequiredSystemFeatures(const BasicDerivation & drv) const
{
// FIXME: cache this?
StringSet res;
for (auto & i : requiredSystemFeatures)
res.insert(i);
if (!drv.type().hasKnownOutputPaths())
res.insert("ca-derivations");
return res;
}
bool DerivationOptions::canBuildLocally(Store & localStore, const BasicDerivation & drv) const
{
if (drv.platform != settings.thisSystem.get() && !settings.extraPlatforms.get().count(drv.platform)
&& !drv.isBuiltin())
return false;
if (settings.maxBuildJobs.get() == 0 && !drv.isBuiltin())
return false;
for (auto & feature : getRequiredSystemFeatures(drv))
if (!localStore.systemFeatures.get().count(feature))
return false;
return true;
}
bool DerivationOptions::willBuildLocally(Store & localStore, const BasicDerivation & drv) const
{
return preferLocalBuild && canBuildLocally(localStore, drv);
}
bool DerivationOptions::substitutesAllowed() const
{
return settings.alwaysAllowSubstitutes ? true : allowSubstitutes;
}
bool DerivationOptions::useUidRange(const BasicDerivation & drv) const
{
return getRequiredSystemFeatures(drv).count("uid-range");
}
}
namespace nlohmann {
using namespace nix;
DerivationOptions adl_serializer<DerivationOptions>::from_json(const json & json)
{
return {
.outputChecks = [&]() -> OutputChecksVariant {
auto outputChecks = getObject(valueAt(json, "outputChecks"));
auto forAllOutputsOpt = optionalValueAt(outputChecks, "forAllOutputs");
auto perOutputOpt = optionalValueAt(outputChecks, "perOutput");
if (forAllOutputsOpt && !perOutputOpt) {
return static_cast<OutputChecks>(*forAllOutputsOpt);
} else if (perOutputOpt && !forAllOutputsOpt) {
return static_cast<std::map<std::string, OutputChecks>>(*perOutputOpt);
} else {
throw Error("Exactly one of 'perOutput' or 'forAllOutputs' is required");
}
}(),
.unsafeDiscardReferences = valueAt(json, "unsafeDiscardReferences"),
.passAsFile = getStringSet(valueAt(json, "passAsFile")),
.additionalSandboxProfile = getString(valueAt(json, "additionalSandboxProfile")),
.noChroot = getBoolean(valueAt(json, "noChroot")),
.impureHostDeps = getStringSet(valueAt(json, "impureHostDeps")),
.impureEnvVars = getStringSet(valueAt(json, "impureEnvVars")),
.allowLocalNetworking = getBoolean(valueAt(json, "allowLocalNetworking")),
.requiredSystemFeatures = getStringSet(valueAt(json, "requiredSystemFeatures")),
.preferLocalBuild = getBoolean(valueAt(json, "preferLocalBuild")),
.allowSubstitutes = getBoolean(valueAt(json, "allowSubstitutes")),
};
}
void adl_serializer<DerivationOptions>::to_json(json & json, DerivationOptions o)
{
json["outputChecks"] = std::visit(
overloaded{
[&](const OutputChecks & checks) {
nlohmann::json outputChecks;
outputChecks["forAllOutputs"] = checks;
return outputChecks;
},
[&](const std::map<std::string, OutputChecks> & checksPerOutput) {
nlohmann::json outputChecks;
outputChecks["perOutput"] = checksPerOutput;
return outputChecks;
},
},
o.outputChecks);
json["unsafeDiscardReferences"] = o.unsafeDiscardReferences;
json["passAsFile"] = o.passAsFile;
json["additionalSandboxProfile"] = o.additionalSandboxProfile;
json["noChroot"] = o.noChroot;
json["impureHostDeps"] = o.impureHostDeps;
json["impureEnvVars"] = o.impureEnvVars;
json["allowLocalNetworking"] = o.allowLocalNetworking;
json["requiredSystemFeatures"] = o.requiredSystemFeatures;
json["preferLocalBuild"] = o.preferLocalBuild;
json["allowSubstitutes"] = o.allowSubstitutes;
}
DerivationOptions::OutputChecks adl_serializer<DerivationOptions::OutputChecks>::from_json(const json & json)
{
return {
.ignoreSelfRefs = getBoolean(valueAt(json, "ignoreSelfRefs")),
.allowedReferences = nullableValueAt(json, "allowedReferences"),
.disallowedReferences = getStringSet(valueAt(json, "disallowedReferences")),
.allowedRequisites = nullableValueAt(json, "allowedRequisites"),
.disallowedRequisites = getStringSet(valueAt(json, "disallowedRequisites")),
};
}
void adl_serializer<DerivationOptions::OutputChecks>::to_json(json & json, DerivationOptions::OutputChecks c)
{
json["ignoreSelfRefs"] = c.ignoreSelfRefs;
json["allowedReferences"] = c.allowedReferences;
json["disallowedReferences"] = c.disallowedReferences;
json["allowedRequisites"] = c.allowedRequisites;
json["disallowedRequisites"] = c.disallowedRequisites;
}
}