Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 28 additions & 28 deletions src/libstore-tests/derivation-advanced-attrs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_defaults)

auto drvPath = writeDerivation(*this->store, got, NoRepair, true);

ParsedDerivation parsedDrv(got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
auto parsedDrv = StructuredAttrs::tryParse(got.env);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, parsedDrv ? &*parsedDrv : nullptr);

EXPECT_TRUE(!parsedDrv.hasStructuredAttrs());
EXPECT_TRUE(!parsedDrv);

EXPECT_EQ(options.additionalSandboxProfile, "");
EXPECT_EQ(options.noChroot, false);
Expand Down Expand Up @@ -143,8 +143,8 @@ TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_defaults)

auto drvPath = writeDerivation(*this->store, got, NoRepair, true);

ParsedDerivation parsedDrv(got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
auto parsedDrv = StructuredAttrs::tryParse(got.env);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, parsedDrv ? &*parsedDrv : nullptr);

EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{});
});
Expand All @@ -157,8 +157,8 @@ TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_defaults)

auto drvPath = writeDerivation(*this->store, got, NoRepair, true);

ParsedDerivation parsedDrv(got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
auto parsedDrv = StructuredAttrs::tryParse(got.env);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, parsedDrv ? &*parsedDrv : nullptr);

EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{"ca-derivations"});
});
Expand All @@ -171,10 +171,10 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes)

auto drvPath = writeDerivation(*this->store, got, NoRepair, true);

ParsedDerivation parsedDrv(got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
auto parsedDrv = StructuredAttrs::tryParse(got.env);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, parsedDrv ? &*parsedDrv : nullptr);

EXPECT_TRUE(!parsedDrv.hasStructuredAttrs());
EXPECT_TRUE(!parsedDrv);

EXPECT_EQ(options.additionalSandboxProfile, "sandcastle");
EXPECT_EQ(options.noChroot, true);
Expand All @@ -195,8 +195,8 @@ TEST_F(DerivationAdvancedAttrsTest, advancedAttributes)

auto drvPath = writeDerivation(*this->store, got, NoRepair, true);

ParsedDerivation parsedDrv(got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
auto parsedDrv = StructuredAttrs::tryParse(got.env);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, parsedDrv ? &*parsedDrv : nullptr);

EXPECT_EQ(
options.exportReferencesGraph,
Expand Down Expand Up @@ -243,8 +243,8 @@ TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes)

auto drvPath = writeDerivation(*this->store, got, NoRepair, true);

ParsedDerivation parsedDrv(got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
auto parsedDrv = StructuredAttrs::tryParse(got.env);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, parsedDrv ? &*parsedDrv : nullptr);

EXPECT_EQ(
options.exportReferencesGraph,
Expand Down Expand Up @@ -296,10 +296,10 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs_d

auto drvPath = writeDerivation(*this->store, got, NoRepair, true);

ParsedDerivation parsedDrv(got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
auto parsedDrv = StructuredAttrs::tryParse(got.env);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, parsedDrv ? &*parsedDrv : nullptr);

EXPECT_TRUE(parsedDrv.hasStructuredAttrs());
EXPECT_TRUE(parsedDrv);

EXPECT_EQ(options.additionalSandboxProfile, "");
EXPECT_EQ(options.noChroot, false);
Expand Down Expand Up @@ -330,8 +330,8 @@ TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs_defaults)

auto drvPath = writeDerivation(*this->store, got, NoRepair, true);

ParsedDerivation parsedDrv(got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
auto parsedDrv = StructuredAttrs::tryParse(got.env);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, parsedDrv ? &*parsedDrv : nullptr);

EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{});
});
Expand All @@ -344,8 +344,8 @@ TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs_default

auto drvPath = writeDerivation(*this->store, got, NoRepair, true);

ParsedDerivation parsedDrv(got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
auto parsedDrv = StructuredAttrs::tryParse(got.env);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, parsedDrv ? &*parsedDrv : nullptr);

EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{"ca-derivations"});
});
Expand All @@ -358,10 +358,10 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs)

auto drvPath = writeDerivation(*this->store, got, NoRepair, true);

ParsedDerivation parsedDrv(got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
auto parsedDrv = StructuredAttrs::tryParse(got.env);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, parsedDrv ? &*parsedDrv : nullptr);

EXPECT_TRUE(parsedDrv.hasStructuredAttrs());
EXPECT_TRUE(parsedDrv);

EXPECT_EQ(options.additionalSandboxProfile, "sandcastle");
EXPECT_EQ(options.noChroot, true);
Expand Down Expand Up @@ -392,8 +392,8 @@ TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs)

auto drvPath = writeDerivation(*this->store, got, NoRepair, true);

ParsedDerivation parsedDrv(got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
auto parsedDrv = StructuredAttrs::tryParse(got.env);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, parsedDrv ? &*parsedDrv : nullptr);

EXPECT_EQ(
options.exportReferencesGraph,
Expand Down Expand Up @@ -445,8 +445,8 @@ TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs)

auto drvPath = writeDerivation(*this->store, got, NoRepair, true);

ParsedDerivation parsedDrv(got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
auto parsedDrv = StructuredAttrs::tryParse(got.env);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, parsedDrv ? &*parsedDrv : nullptr);

EXPECT_EQ(
options.exportReferencesGraph,
Expand Down
7 changes: 5 additions & 2 deletions src/libstore/build/derivation-goal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,12 @@ Goal::Co DerivationGoal::haveDerivation()
{
trace("have derivation");

parsedDrv = std::make_unique<ParsedDerivation>(*drv);
if (auto parsedOpt = StructuredAttrs::tryParse(drv->env)) {
parsedDrv = std::make_unique<StructuredAttrs>(*parsedOpt);
}
try {
drvOptions = std::make_unique<DerivationOptions>(DerivationOptions::fromParsedDerivation(*parsedDrv));
drvOptions = std::make_unique<DerivationOptions>(
DerivationOptions::fromStructuredAttrs(drv->env, parsedDrv.get()));
} catch (Error & e) {
e.addTrace({}, "while parsing derivation '%s'", worker.store.printStorePath(drvPath));
throw;
Expand Down
140 changes: 108 additions & 32 deletions src/libstore/derivation-options.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "nix/store/derivation-options.hh"
#include "nix/util/json-utils.hh"
#include "nix/store/parsed-derivations.hh"
#include "nix/store/derivations.hh"
#include "nix/store/store-api.hh"
#include "nix/util/types.hh"
#include "nix/util/util.hh"

Expand All @@ -11,48 +13,122 @@

namespace nix {

static std::optional<std::string>
getStringAttr(const StringMap & env, const StructuredAttrs * parsed, const std::string & name)
{
if (parsed) {
auto i = parsed->structuredAttrs.find(name);
if (i == parsed->structuredAttrs.end())
return {};
else {
if (!i->is_string())
throw Error("attribute '%s' of must be a string", name);
return i->get<std::string>();
}
} else {
auto i = env.find(name);
if (i == env.end())
return {};
else
return i->second;
}
}

static bool getBoolAttr(const StringMap & env, const StructuredAttrs * parsed, const std::string & name, bool def)
{
if (parsed) {
auto i = parsed->structuredAttrs.find(name);
if (i == parsed->structuredAttrs.end())
return def;
else {
if (!i->is_boolean())
throw Error("attribute '%s' must be a Boolean", name);
return i->get<bool>();
}
} else {
auto i = env.find(name);
if (i == env.end())
return def;
else
return i->second == "1";
}
}

static std::optional<Strings>
getStringsAttr(const StringMap & env, const StructuredAttrs * parsed, const std::string & name)
{
if (parsed) {
auto i = parsed->structuredAttrs.find(name);
if (i == parsed->structuredAttrs.end())
return {};
else {
if (!i->is_array())
throw Error("attribute '%s' must be a list of strings", name);
Strings 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.push_back(j->get<std::string>());
}
return res;
}
} else {
auto i = env.find(name);
if (i == env.end())
return {};
else
return tokenizeString<Strings>(i->second);
}
}

static std::optional<StringSet>
getStringSetAttr(const StringMap & env, const StructuredAttrs * parsed, const std::string & name)
{
auto ss = getStringsAttr(env, parsed, name);
return ss ? (std::optional{StringSet{ss->begin(), ss->end()}}) : (std::optional<StringSet>{});
}

using OutputChecks = DerivationOptions::OutputChecks;

using OutputChecksVariant = std::variant<OutputChecks, std::map<std::string, OutputChecks>>;

DerivationOptions DerivationOptions::fromParsedDerivation(const ParsedDerivation & parsed, bool shouldWarn)
DerivationOptions
DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAttrs * parsed, bool shouldWarn)
{
DerivationOptions defaults = {};

auto structuredAttrs = parsed.structuredAttrs.get();

if (shouldWarn && structuredAttrs) {
if (get(*structuredAttrs, "allowedReferences")) {
if (shouldWarn && parsed) {
if (get(parsed->structuredAttrs, "allowedReferences")) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'allowedReferences'; use 'outputChecks' instead");
}
if (get(*structuredAttrs, "allowedRequisites")) {
if (get(parsed->structuredAttrs, "allowedRequisites")) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'allowedRequisites'; use 'outputChecks' instead");
}
if (get(*structuredAttrs, "disallowedRequisites")) {
if (get(parsed->structuredAttrs, "disallowedRequisites")) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'disallowedRequisites'; use 'outputChecks' instead");
}
if (get(*structuredAttrs, "disallowedReferences")) {
if (get(parsed->structuredAttrs, "disallowedReferences")) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'disallowedReferences'; use 'outputChecks' instead");
}
if (get(*structuredAttrs, "maxSize")) {
if (get(parsed->structuredAttrs, "maxSize")) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'maxSize'; use 'outputChecks' instead");
}
if (get(*structuredAttrs, "maxClosureSize")) {
if (get(parsed->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()) {
if (parsed) {
std::map<std::string, OutputChecks> res;
if (auto outputChecks = get(*structuredAttrs, "outputChecks")) {
if (auto outputChecks = get(parsed->structuredAttrs, "outputChecks")) {
for (auto & [outputName, output] : getObject(*outputChecks)) {
OutputChecks checks;

Expand Down Expand Up @@ -90,19 +166,19 @@ DerivationOptions DerivationOptions::fromParsedDerivation(const ParsedDerivation
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{}),
.allowedReferences = getStringSetAttr(env, parsed, "allowedReferences"),
.disallowedReferences = getStringSetAttr(env, parsed, "disallowedReferences").value_or(StringSet{}),
.allowedRequisites = getStringSetAttr(env, parsed, "allowedRequisites"),
.disallowedRequisites = getStringSetAttr(env, parsed, "disallowedRequisites").value_or(StringSet{}),
};
}
}(),
.unsafeDiscardReferences =
[&] {
std::map<std::string, bool> res;

if (auto structuredAttrs = parsed.structuredAttrs.get()) {
if (auto udr = get(*structuredAttrs, "unsafeDiscardReferences")) {
if (parsed) {
if (auto udr = get(parsed->structuredAttrs, "unsafeDiscardReferences")) {
for (auto & [outputName, output] : getObject(*udr)) {
if (!output.is_boolean())
throw Error("attribute 'unsafeDiscardReferences.\"%s\"' must be a Boolean", outputName);
Expand All @@ -116,8 +192,8 @@ DerivationOptions DerivationOptions::fromParsedDerivation(const ParsedDerivation
.passAsFile =
[&] {
StringSet res;
if (auto * passAsFileString = get(parsed.drv.env, "passAsFile")) {
if (parsed.hasStructuredAttrs()) {
if (auto * passAsFileString = get(env, "passAsFile")) {
if (parsed) {
if (shouldWarn) {
warn(
"'structuredAttrs' disables the effect of the top-level attribute 'passAsFile'; because all JSON is always passed via file");
Expand All @@ -132,18 +208,18 @@ DerivationOptions DerivationOptions::fromParsedDerivation(const ParsedDerivation
[&] {
std::map<std::string, StringSet> ret;

if (auto structuredAttrs = parsed.structuredAttrs.get()) {
auto e = optionalValueAt(*structuredAttrs, "exportReferencesGraph");
if (parsed) {
auto e = optionalValueAt(parsed->structuredAttrs, "exportReferencesGraph");
if (!e || !e->is_object())
return ret;
for (auto & [key, storePathsJson] : getObject(*e)) {
ret.insert_or_assign(key, storePathsJson);
}
} else {
auto s = getOr(parsed.drv.env, "exportReferencesGraph", "");
auto s = getOr(env, "exportReferencesGraph", "");
Strings ss = tokenizeString<Strings>(s);
if (ss.size() % 2 != 0)
throw BuildError("odd number of tokens in 'exportReferencesGraph': '%1%'", s);
throw Error("odd number of tokens in 'exportReferencesGraph': '%1%'", s);
for (Strings::iterator i = ss.begin(); i != ss.end();) {
auto fileName = std::move(*i++);
static std::regex regex("[A-Za-z_][A-Za-z0-9_.-]*");
Expand All @@ -157,15 +233,15 @@ DerivationOptions DerivationOptions::fromParsedDerivation(const ParsedDerivation
return ret;
}(),
.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),
getStringAttr(env, parsed, "__sandboxProfile").value_or(defaults.additionalSandboxProfile),
.noChroot = getBoolAttr(env, parsed, "__noChroot", defaults.noChroot),
.impureHostDeps = getStringSetAttr(env, parsed, "__impureHostDeps").value_or(defaults.impureHostDeps),
.impureEnvVars = getStringSetAttr(env, parsed, "impureEnvVars").value_or(defaults.impureEnvVars),
.allowLocalNetworking = getBoolAttr(env, parsed, "__darwinAllowLocalNetworking", defaults.allowLocalNetworking),
.requiredSystemFeatures =
parsed.getStringSetAttr("requiredSystemFeatures").value_or(defaults.requiredSystemFeatures),
.preferLocalBuild = parsed.getBoolAttr("preferLocalBuild", defaults.preferLocalBuild),
.allowSubstitutes = parsed.getBoolAttr("allowSubstitutes", defaults.allowSubstitutes),
getStringSetAttr(env, parsed, "requiredSystemFeatures").value_or(defaults.requiredSystemFeatures),
.preferLocalBuild = getBoolAttr(env, parsed, "preferLocalBuild", defaults.preferLocalBuild),
.allowSubstitutes = getBoolAttr(env, parsed, "allowSubstitutes", defaults.allowSubstitutes),
};
}

Expand Down
Loading