Skip to content

Commit 313ec2f

Browse files
committed
Scrap ParsedDerivation for parts
Only a much smaller `StructuredAttrs` remains, the rest is is now moved to `DerivationOptions`. This gets us quite close to `std::optional<StructuredAttrs>` and `DerivationOptions` being included in `Derivation` as fields.
1 parent 2093894 commit 313ec2f

10 files changed

Lines changed: 202 additions & 206 deletions

File tree

src/libstore-tests/derivation-advanced-attrs.cc

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,11 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_defaults)
8181

8282
auto drvPath = writeDerivation(*store, got, NoRepair, true);
8383

84-
ParsedDerivation parsedDrv(got.env);
85-
DerivationOptions options = DerivationOptions::fromParsedDerivation(*store, parsedDrv);
84+
auto parsedDrv = StructuredAttrs::tryParse(got.env);
85+
DerivationOptions options =
86+
DerivationOptions::fromStructuredAttrs(*store, got.env, parsedDrv ? &*parsedDrv : nullptr);
8687

87-
EXPECT_TRUE(!parsedDrv.hasStructuredAttrs());
88+
EXPECT_TRUE(!parsedDrv);
8889

8990
EXPECT_EQ(options.additionalSandboxProfile, "");
9091
EXPECT_EQ(options.noChroot, false);
@@ -116,12 +117,13 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes)
116117

117118
auto drvPath = writeDerivation(*store, got, NoRepair, true);
118119

119-
ParsedDerivation parsedDrv(got.env);
120-
DerivationOptions options = DerivationOptions::fromParsedDerivation(*store, parsedDrv);
120+
auto parsedDrv = StructuredAttrs::tryParse(got.env);
121+
DerivationOptions options =
122+
DerivationOptions::fromStructuredAttrs(*store, got.env, parsedDrv ? &*parsedDrv : nullptr);
121123

122124
StringSet systemFeatures{"rainbow", "uid-range"};
123125

124-
EXPECT_TRUE(!parsedDrv.hasStructuredAttrs());
126+
EXPECT_TRUE(!parsedDrv);
125127

126128
EXPECT_EQ(options.additionalSandboxProfile, "sandcastle");
127129
EXPECT_EQ(options.noChroot, true);
@@ -157,10 +159,11 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttr
157159

158160
auto drvPath = writeDerivation(*store, got, NoRepair, true);
159161

160-
ParsedDerivation parsedDrv(got.env);
161-
DerivationOptions options = DerivationOptions::fromParsedDerivation(*store, parsedDrv);
162+
auto parsedDrv = StructuredAttrs::tryParse(got.env);
163+
DerivationOptions options =
164+
DerivationOptions::fromStructuredAttrs(*store, got.env, parsedDrv ? &*parsedDrv : nullptr);
162165

163-
EXPECT_TRUE(parsedDrv.hasStructuredAttrs());
166+
EXPECT_TRUE(parsedDrv);
164167

165168
EXPECT_EQ(options.additionalSandboxProfile, "");
166169
EXPECT_EQ(options.noChroot, false);
@@ -191,12 +194,13 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttr
191194

192195
auto drvPath = writeDerivation(*store, got, NoRepair, true);
193196

194-
ParsedDerivation parsedDrv(got.env);
195-
DerivationOptions options = DerivationOptions::fromParsedDerivation(*store, parsedDrv);
197+
auto parsedDrv = StructuredAttrs::tryParse(got.env);
198+
DerivationOptions options =
199+
DerivationOptions::fromStructuredAttrs(*store, got.env, parsedDrv ? &*parsedDrv : nullptr);
196200

197201
StringSet systemFeatures{"rainbow", "uid-range"};
198202

199-
EXPECT_TRUE(parsedDrv.hasStructuredAttrs());
203+
EXPECT_TRUE(parsedDrv);
200204

201205
EXPECT_EQ(options.additionalSandboxProfile, "sandcastle");
202206
EXPECT_EQ(options.noChroot, true);

src/libstore/build/derivation-goal.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,12 @@ Goal::Co DerivationGoal::haveDerivation()
180180
{
181181
trace("have derivation");
182182

183-
parsedDrv = std::make_unique<ParsedDerivation>(drv->env);
183+
if (auto parsedOpt = StructuredAttrs::tryParse(drv->env)) {
184+
parsedDrv = std::make_unique<StructuredAttrs>(*parsedOpt);
185+
}
184186
try {
185187
drvOptions = std::make_unique<DerivationOptions>(
186-
DerivationOptions::fromParsedDerivation(worker.store, *parsedDrv));
188+
DerivationOptions::fromStructuredAttrs(worker.store, drv->env, parsedDrv.get()));
187189
} catch (Error & e) {
188190
e.addTrace({}, "while parsing derivation '%s'", worker.store.printStorePath(drvPath));
189191
throw;

src/libstore/build/derivation-goal.hh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
///@file
33

44
#include "parsed-derivations.hh"
5+
#include "derivations.hh"
56
#include "derivation-options.hh"
67
#ifndef _WIN32
78
# include "user-lock.hh"
@@ -150,7 +151,7 @@ struct DerivationGoal : public Goal
150151
*/
151152
std::unique_ptr<Derivation> drv;
152153

153-
std::unique_ptr<ParsedDerivation> parsedDrv;
154+
std::unique_ptr<StructuredAttrs> parsedDrv;
154155
std::unique_ptr<DerivationOptions> drvOptions;
155156

156157
/**

src/libstore/derivation-options.cc

Lines changed: 108 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "derivation-options.hh"
22
#include "json-utils.hh"
33
#include "parsed-derivations.hh"
4+
#include "derivations.hh"
5+
#include "store-api.hh"
46
#include "types.hh"
57
#include "util.hh"
68

@@ -11,49 +13,122 @@
1113

1214
namespace nix {
1315

16+
static std::optional<std::string>
17+
getStringAttr(const StringMap & env, const StructuredAttrs * parsed, const std::string & name)
18+
{
19+
if (parsed) {
20+
auto i = parsed->structuredAttrs.find(name);
21+
if (i == parsed->structuredAttrs.end())
22+
return {};
23+
else {
24+
if (!i->is_string())
25+
throw Error("attribute '%s' of must be a string", name);
26+
return i->get<std::string>();
27+
}
28+
} else {
29+
auto i = env.find(name);
30+
if (i == env.end())
31+
return {};
32+
else
33+
return i->second;
34+
}
35+
}
36+
37+
static bool getBoolAttr(const StringMap & env, const StructuredAttrs * parsed, const std::string & name, bool def)
38+
{
39+
if (parsed) {
40+
auto i = parsed->structuredAttrs.find(name);
41+
if (i == parsed->structuredAttrs.end())
42+
return def;
43+
else {
44+
if (!i->is_boolean())
45+
throw Error("attribute '%s' must be a Boolean", name);
46+
return i->get<bool>();
47+
}
48+
} else {
49+
auto i = env.find(name);
50+
if (i == env.end())
51+
return def;
52+
else
53+
return i->second == "1";
54+
}
55+
}
56+
57+
static std::optional<Strings>
58+
getStringsAttr(const StringMap & env, const StructuredAttrs * parsed, const std::string & name)
59+
{
60+
if (parsed) {
61+
auto i = parsed->structuredAttrs.find(name);
62+
if (i == parsed->structuredAttrs.end())
63+
return {};
64+
else {
65+
if (!i->is_array())
66+
throw Error("attribute '%s' must be a list of strings", name);
67+
Strings res;
68+
for (auto j = i->begin(); j != i->end(); ++j) {
69+
if (!j->is_string())
70+
throw Error("attribute '%s' must be a list of strings", name);
71+
res.push_back(j->get<std::string>());
72+
}
73+
return res;
74+
}
75+
} else {
76+
auto i = env.find(name);
77+
if (i == env.end())
78+
return {};
79+
else
80+
return tokenizeString<Strings>(i->second);
81+
}
82+
}
83+
84+
static std::optional<StringSet>
85+
getStringSetAttr(const StringMap & env, const StructuredAttrs * parsed, const std::string & name)
86+
{
87+
auto ss = getStringsAttr(env, parsed, name);
88+
return ss ? (std::optional{StringSet{ss->begin(), ss->end()}}) : (std::optional<StringSet>{});
89+
}
90+
1491
using OutputChecks = DerivationOptions::OutputChecks;
1592

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

18-
DerivationOptions
19-
DerivationOptions::fromParsedDerivation(const StoreDirConfig & store, const ParsedDerivation & parsed, bool shouldWarn)
95+
DerivationOptions DerivationOptions::fromStructuredAttrs(
96+
const StoreDirConfig & store, const StringMap & env, const StructuredAttrs * parsed, bool shouldWarn)
2097
{
2198
DerivationOptions defaults = {};
2299

23-
auto structuredAttrs = parsed.structuredAttrs.get();
24-
25-
if (shouldWarn && structuredAttrs) {
26-
if (get(*structuredAttrs, "allowedReferences")) {
100+
if (shouldWarn && parsed) {
101+
if (get(parsed->structuredAttrs, "allowedReferences")) {
27102
warn(
28103
"'structuredAttrs' disables the effect of the top-level attribute 'allowedReferences'; use 'outputChecks' instead");
29104
}
30-
if (get(*structuredAttrs, "allowedRequisites")) {
105+
if (get(parsed->structuredAttrs, "allowedRequisites")) {
31106
warn(
32107
"'structuredAttrs' disables the effect of the top-level attribute 'allowedRequisites'; use 'outputChecks' instead");
33108
}
34-
if (get(*structuredAttrs, "disallowedRequisites")) {
109+
if (get(parsed->structuredAttrs, "disallowedRequisites")) {
35110
warn(
36111
"'structuredAttrs' disables the effect of the top-level attribute 'disallowedRequisites'; use 'outputChecks' instead");
37112
}
38-
if (get(*structuredAttrs, "disallowedReferences")) {
113+
if (get(parsed->structuredAttrs, "disallowedReferences")) {
39114
warn(
40115
"'structuredAttrs' disables the effect of the top-level attribute 'disallowedReferences'; use 'outputChecks' instead");
41116
}
42-
if (get(*structuredAttrs, "maxSize")) {
117+
if (get(parsed->structuredAttrs, "maxSize")) {
43118
warn(
44119
"'structuredAttrs' disables the effect of the top-level attribute 'maxSize'; use 'outputChecks' instead");
45120
}
46-
if (get(*structuredAttrs, "maxClosureSize")) {
121+
if (get(parsed->structuredAttrs, "maxClosureSize")) {
47122
warn(
48123
"'structuredAttrs' disables the effect of the top-level attribute 'maxClosureSize'; use 'outputChecks' instead");
49124
}
50125
}
51126

52127
return {
53128
.outputChecks = [&]() -> OutputChecksVariant {
54-
if (auto structuredAttrs = parsed.structuredAttrs.get()) {
129+
if (parsed) {
55130
std::map<std::string, OutputChecks> res;
56-
if (auto outputChecks = get(*structuredAttrs, "outputChecks")) {
131+
if (auto outputChecks = get(parsed->structuredAttrs, "outputChecks")) {
57132
for (auto & [outputName, output] : getObject(*outputChecks)) {
58133
OutputChecks checks;
59134

@@ -91,19 +166,19 @@ DerivationOptions::fromParsedDerivation(const StoreDirConfig & store, const Pars
91166
return OutputChecks{
92167
// legacy non-structured-attributes case
93168
.ignoreSelfRefs = true,
94-
.allowedReferences = parsed.getStringSetAttr("allowedReferences"),
95-
.disallowedReferences = parsed.getStringSetAttr("disallowedReferences").value_or(StringSet{}),
96-
.allowedRequisites = parsed.getStringSetAttr("allowedRequisites"),
97-
.disallowedRequisites = parsed.getStringSetAttr("disallowedRequisites").value_or(StringSet{}),
169+
.allowedReferences = getStringSetAttr(env, parsed, "allowedReferences"),
170+
.disallowedReferences = getStringSetAttr(env, parsed, "disallowedReferences").value_or(StringSet{}),
171+
.allowedRequisites = getStringSetAttr(env, parsed, "allowedRequisites"),
172+
.disallowedRequisites = getStringSetAttr(env, parsed, "disallowedRequisites").value_or(StringSet{}),
98173
};
99174
}
100175
}(),
101176
.unsafeDiscardReferences =
102177
[&] {
103178
std::map<std::string, bool> res;
104179

105-
if (auto structuredAttrs = parsed.structuredAttrs.get()) {
106-
if (auto udr = get(*structuredAttrs, "unsafeDiscardReferences")) {
180+
if (parsed) {
181+
if (auto udr = get(parsed->structuredAttrs, "unsafeDiscardReferences")) {
107182
for (auto & [outputName, output] : getObject(*udr)) {
108183
if (!output.is_boolean())
109184
throw Error("attribute 'unsafeDiscardReferences.\"%s\"' must be a Boolean", outputName);
@@ -117,8 +192,8 @@ DerivationOptions::fromParsedDerivation(const StoreDirConfig & store, const Pars
117192
.passAsFile =
118193
[&] {
119194
StringSet res;
120-
if (auto * passAsFileString = get(parsed.env, "passAsFile")) {
121-
if (parsed.hasStructuredAttrs()) {
195+
if (auto * passAsFileString = get(env, "passAsFile")) {
196+
if (parsed) {
122197
if (shouldWarn) {
123198
warn(
124199
"'structuredAttrs' disables the effect of the top-level attribute 'passAsFile'; because all JSON is always passed via file");
@@ -133,8 +208,8 @@ DerivationOptions::fromParsedDerivation(const StoreDirConfig & store, const Pars
133208
[&] {
134209
std::map<std::string, StorePathSet> ret;
135210

136-
if (auto structuredAttrs = parsed.structuredAttrs.get()) {
137-
auto e = optionalValueAt(*structuredAttrs, "exportReferencesGraph");
211+
if (parsed) {
212+
auto e = optionalValueAt(parsed->structuredAttrs, "exportReferencesGraph");
138213
if (!e || !e->is_object())
139214
return ret;
140215
for (auto & [key, storePathsJson] : getObject(*e)) {
@@ -144,10 +219,10 @@ DerivationOptions::fromParsedDerivation(const StoreDirConfig & store, const Pars
144219
ret.insert_or_assign(key, std::move(storePaths));
145220
}
146221
} else {
147-
auto s = getOr(parsed.env, "exportReferencesGraph", "");
222+
auto s = getOr(env, "exportReferencesGraph", "");
148223
Strings ss = tokenizeString<Strings>(s);
149224
if (ss.size() % 2 != 0)
150-
throw BuildError("odd number of tokens in 'exportReferencesGraph': '%1%'", s);
225+
throw Error("odd number of tokens in 'exportReferencesGraph': '%1%'", s);
151226
for (Strings::iterator i = ss.begin(); i != ss.end();) {
152227
auto fileName = std::move(*i++);
153228
static std::regex regex("[A-Za-z_][A-Za-z0-9_.-]*");
@@ -163,15 +238,15 @@ DerivationOptions::fromParsedDerivation(const StoreDirConfig & store, const Pars
163238
return ret;
164239
}(),
165240
.additionalSandboxProfile =
166-
parsed.getStringAttr("__sandboxProfile").value_or(defaults.additionalSandboxProfile),
167-
.noChroot = parsed.getBoolAttr("__noChroot", defaults.noChroot),
168-
.impureHostDeps = parsed.getStringSetAttr("__impureHostDeps").value_or(defaults.impureHostDeps),
169-
.impureEnvVars = parsed.getStringSetAttr("impureEnvVars").value_or(defaults.impureEnvVars),
170-
.allowLocalNetworking = parsed.getBoolAttr("__darwinAllowLocalNetworking", defaults.allowLocalNetworking),
241+
getStringAttr(env, parsed, "__sandboxProfile").value_or(defaults.additionalSandboxProfile),
242+
.noChroot = getBoolAttr(env, parsed, "__noChroot", defaults.noChroot),
243+
.impureHostDeps = getStringSetAttr(env, parsed, "__impureHostDeps").value_or(defaults.impureHostDeps),
244+
.impureEnvVars = getStringSetAttr(env, parsed, "impureEnvVars").value_or(defaults.impureEnvVars),
245+
.allowLocalNetworking = getBoolAttr(env, parsed, "__darwinAllowLocalNetworking", defaults.allowLocalNetworking),
171246
.requiredSystemFeatures =
172-
parsed.getStringSetAttr("requiredSystemFeatures").value_or(defaults.requiredSystemFeatures),
173-
.preferLocalBuild = parsed.getBoolAttr("preferLocalBuild", defaults.preferLocalBuild),
174-
.allowSubstitutes = parsed.getBoolAttr("allowSubstitutes", defaults.allowSubstitutes),
247+
getStringSetAttr(env, parsed, "requiredSystemFeatures").value_or(defaults.requiredSystemFeatures),
248+
.preferLocalBuild = getBoolAttr(env, parsed, "preferLocalBuild", defaults.preferLocalBuild),
249+
.allowSubstitutes = getBoolAttr(env, parsed, "allowSubstitutes", defaults.allowSubstitutes),
175250
};
176251
}
177252

src/libstore/derivation-options.hh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ namespace nix {
1414

1515
class Store;
1616
struct BasicDerivation;
17-
class ParsedDerivation;
17+
struct StructuredAttrs;
1818

1919
/**
2020
* This represents all the special options on a `Derivation`.
2121
*
2222
* Currently, these options are parsed from the environment variables
23-
* with the aid of `ParsedDerivation`.
23+
* with the aid of `StructuredAttrs`.
2424
*
2525
* The first goal of this data type is to make sure that no other code
26-
* uses `ParsedDerivation` to ad-hoc parse some additional options. That
26+
* uses `StructuredAttrs` to ad-hoc parse some additional options. That
2727
* ensures this data type is up to date and fully correct.
2828
*
2929
* The second goal of this data type is to allow an alternative to
@@ -174,8 +174,8 @@ struct DerivationOptions
174174
* (e.g. JSON) but is necessary for supporing old formats (e.g.
175175
* ATerm).
176176
*/
177-
static DerivationOptions
178-
fromParsedDerivation(const StoreDirConfig & store, const ParsedDerivation & parsed, bool shouldWarn = true);
177+
static DerivationOptions fromStructuredAttrs(
178+
const StoreDirConfig & store, const StringMap & env, const StructuredAttrs * parsed, bool shouldWarn = true);
179179

180180
/**
181181
* @param drv Must be the same derivation we parsed this from. In

src/libstore/misc.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,13 @@ void Store::queryMissing(const std::vector<DerivedPath> & targets,
222222
if (knownOutputPaths && invalid.empty()) return;
223223

224224
auto drv = make_ref<Derivation>(derivationFromPath(drvPath));
225-
ParsedDerivation parsedDrv(drv->env);
225+
auto parsedDrv = StructuredAttrs::tryParse(drv->env);
226226
DerivationOptions drvOptions;
227227
try {
228-
drvOptions = DerivationOptions::fromParsedDerivation(*this, parsedDrv);
228+
drvOptions = DerivationOptions::fromStructuredAttrs(
229+
*this,
230+
drv->env,
231+
parsedDrv ? &*parsedDrv : nullptr);
229232
} catch (Error & e) {
230233
e.addTrace({}, "while parsing derivation '%s'", printStorePath(drvPath));
231234
throw;

0 commit comments

Comments
 (0)