Skip to content

Commit 7c3a11e

Browse files
Ericson2314kjeremy
andcommitted
Factor out a new DesugaredEnv from DerivationBuildingGoal
Now we have better separation of the core logic --- an integral part of the store layer spec even --- from the goal mechanism and other minutiae. Co-authored-by: Jeremy Kolb <[email protected]>
1 parent c2782d7 commit 7c3a11e

File tree

8 files changed

+161
-90
lines changed

8 files changed

+161
-90
lines changed

src/libstore/build/derivation-building-goal.cc

Lines changed: 4 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "nix/store/build/derivation-building-goal.hh"
2+
#include "nix/store/build/derivation-env-desugar.hh"
23
#include "nix/store/build/derivation-trampoline-goal.hh"
34
#ifndef _WIN32 // TODO enable build hook on Windows
45
# include "nix/store/build/hook-instance.hh"
@@ -681,8 +682,7 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
681682
assert(localStoreP);
682683

683684
decltype(DerivationBuilderParams::defaultPathsInChroot) defaultPathsInChroot = settings.sandboxPaths.get();
684-
decltype(DerivationBuilderParams::finalEnv) finalEnv;
685-
decltype(DerivationBuilderParams::extraFiles) extraFiles;
685+
DesugaredEnv desugaredEnv;
686686

687687
/* Add the closure of store paths to the chroot. */
688688
StorePathSet closure;
@@ -701,54 +701,7 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
701701
}
702702

703703
try {
704-
if (drv->structuredAttrs) {
705-
auto json = drv->structuredAttrs->prepareStructuredAttrs(
706-
worker.store, *drvOptions, inputPaths, drv->outputs);
707-
708-
finalEnv.insert_or_assign(
709-
"NIX_ATTRS_SH_FILE",
710-
DerivationBuilderParams::EnvEntry{
711-
.nameOfPassAsFile = ".attrs.sh",
712-
.value = StructuredAttrs::writeShell(json),
713-
});
714-
finalEnv.insert_or_assign(
715-
"NIX_ATTRS_JSON_FILE",
716-
DerivationBuilderParams::EnvEntry{
717-
.nameOfPassAsFile = ".attrs.json",
718-
.value = json.dump(),
719-
});
720-
} else {
721-
/* In non-structured mode, set all bindings either directory in the
722-
environment or via a file, as specified by
723-
`DerivationOptions::passAsFile`. */
724-
for (auto & [envName, envValue] : drv->env) {
725-
if (drvOptions->passAsFile.find(envName) == drvOptions->passAsFile.end()) {
726-
finalEnv.insert_or_assign(
727-
envName,
728-
DerivationBuilderParams::EnvEntry{
729-
.nameOfPassAsFile = std::nullopt,
730-
.value = envValue,
731-
});
732-
} else {
733-
auto hash = hashString(HashAlgorithm::SHA256, envName);
734-
finalEnv.insert_or_assign(
735-
envName + "Path",
736-
DerivationBuilderParams::EnvEntry{
737-
.nameOfPassAsFile = ".attr-" + hash.to_string(HashFormat::Nix32, false),
738-
.value = envValue,
739-
});
740-
}
741-
}
742-
743-
/* Handle exportReferencesGraph(), if set. */
744-
for (auto & [fileName, storePaths] : drvOptions->getParsedExportReferencesGraph(worker.store)) {
745-
/* Write closure info to <fileName>. */
746-
extraFiles.insert_or_assign(
747-
fileName,
748-
worker.store.makeValidityRegistration(
749-
worker.store.exportReferences(storePaths, inputPaths), false, false));
750-
}
751-
}
704+
desugaredEnv = DesugaredEnv::create(worker.store, *drv, *drvOptions, inputPaths);
752705
} catch (BuildError & e) {
753706
outputLocks.unlock();
754707
worker.permanentFailure = true;
@@ -770,8 +723,7 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
770723
.buildMode = buildMode,
771724
.defaultPathsInChroot = std::move(defaultPathsInChroot),
772725
.systemFeatures = worker.store.config.systemFeatures.get(),
773-
.finalEnv = std::move(finalEnv),
774-
.extraFiles = std::move(extraFiles),
726+
.desugaredEnv = std::move(desugaredEnv),
775727
});
776728
}
777729

src/libstore/build/derivation-check.hh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#pragma once
2+
///@file
3+
14
#include "nix/store/derivations.hh"
25
#include "nix/store/derivation-options.hh"
36
#include "nix/store/path-info.hh"
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#include "nix/store/build/derivation-env-desugar.hh"
2+
#include "nix/store/store-api.hh"
3+
#include "nix/store/derivations.hh"
4+
#include "nix/store/derivation-options.hh"
5+
6+
namespace nix {
7+
8+
std::string & DesugaredEnv::atFileEnvPair(std::string_view name, std::string fileName)
9+
{
10+
auto & ret = extraFiles[fileName];
11+
variables.insert_or_assign(
12+
std::string{name},
13+
EnvEntry{
14+
.prependBuildDirectory = true,
15+
.value = std::move(fileName),
16+
});
17+
return ret;
18+
}
19+
20+
DesugaredEnv DesugaredEnv::create(
21+
Store & store, const Derivation & drv, const DerivationOptions & drvOptions, const StorePathSet & inputPaths)
22+
{
23+
if (drv.structuredAttrs) {
24+
auto json = drv.structuredAttrs->prepareStructuredAttrs(store, drvOptions, inputPaths, drv.outputs);
25+
26+
DesugaredEnv res;
27+
res.atFileEnvPair("NIX_ATTRS_SH_FILE", ".attrs.sh") = StructuredAttrs::writeShell(json);
28+
res.atFileEnvPair("NIX_ATTRS_JSON_FILE", ".attrs.json") = json.dump();
29+
return res;
30+
} else {
31+
DesugaredEnv res;
32+
33+
/* In non-structured mode, set all bindings either directory in the
34+
environment or via a file, as specified by
35+
`DerivationOptions::passAsFile`. */
36+
for (auto & [envName, envValue] : drv.env) {
37+
if (!drvOptions.passAsFile.contains(envName)) {
38+
res.variables.insert_or_assign(
39+
envName,
40+
EnvEntry{
41+
.value = envValue,
42+
});
43+
} else {
44+
res.atFileEnvPair(
45+
envName + "Path",
46+
".attr-" + hashString(HashAlgorithm::SHA256, envName).to_string(HashFormat::Nix32, false)) =
47+
envValue;
48+
}
49+
}
50+
51+
/* Handle exportReferencesGraph(), if set. */
52+
for (auto & [fileName, storePaths] : drvOptions.getParsedExportReferencesGraph(store)) {
53+
/* Write closure info to <fileName>. */
54+
res.extraFiles.insert_or_assign(
55+
fileName, store.makeValidityRegistration(store.exportReferences(storePaths, inputPaths), false, false));
56+
}
57+
58+
return res;
59+
}
60+
}
61+
62+
} // namespace nix

src/libstore/include/nix/store/build/derivation-builder.hh

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "nix/store/parsed-derivations.hh"
99
#include "nix/util/processes.hh"
1010
#include "nix/store/restricted-store.hh"
11+
#include "nix/store/build/derivation-env-desugar.hh"
1112

1213
namespace nix {
1314

@@ -73,34 +74,7 @@ struct DerivationBuilderParams
7374
*/
7475
StringSet systemFeatures;
7576

76-
struct EnvEntry
77-
{
78-
/**
79-
* Actually, this should be passed as a file, but with a custom
80-
* name (rather than hash-derived name for usual "pass as file").
81-
*/
82-
std::optional<std::string> nameOfPassAsFile;
83-
84-
/**
85-
* String value of env var, or contents of the file
86-
*/
87-
std::string value;
88-
};
89-
90-
/**
91-
* The final environment variables to additionally set, possibly
92-
* indirectly via a file.
93-
*
94-
* This is used by the caller to desugar the "structured attrs"
95-
* mechanism, so `DerivationBuilder` doesn't need to know about it.
96-
*/
97-
std::map<std::string, EnvEntry, std::less<>> finalEnv;
98-
99-
/**
100-
* Inserted in the temp dir, but no file names placed in env, unlike
101-
* `EnvEntry::nameOfPassAsFile` above.
102-
*/
103-
StringMap extraFiles;
77+
DesugaredEnv desugaredEnv;
10478
};
10579

10680
/**
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#pragma once
2+
///@file
3+
4+
#include "nix/util/types.hh"
5+
#include "nix/store/path.hh"
6+
7+
namespace nix {
8+
9+
class Store;
10+
struct Derivation;
11+
struct DerivationOptions;
12+
13+
/**
14+
* Derivations claim to "just" specify their environment variables, but
15+
* actually do a number of different features, such as "structured
16+
* attrs", "pass as file", and "export references graph", things are
17+
* more complicated then they appear.
18+
*
19+
* The good news is that we can simplify all that to the following view,
20+
* where environment variables and extra files are specified exactly,
21+
* with no special cases.
22+
*
23+
* Because we have `DesugaredEnv`, `DerivationBuilder` doesn't need to
24+
* know about any of those above features, and their special case.
25+
*/
26+
struct DesugaredEnv
27+
{
28+
struct EnvEntry
29+
{
30+
/**
31+
* Whether to prepend the (inside via) path to the sandbox build
32+
* directory to `value`. This is useful for when the env var
33+
* should point to a file visible to the builder.
34+
*/
35+
bool prependBuildDirectory = false;
36+
37+
/**
38+
* String value of env var, or contents of the file.
39+
*/
40+
std::string value;
41+
};
42+
43+
/**
44+
* The final environment variables to set.
45+
*/
46+
std::map<std::string, EnvEntry, std::less<>> variables;
47+
48+
/**
49+
* Extra file to be placed in the build directory.
50+
*
51+
* @note `EnvEntry::prependBuildDirectory` can be used to refer to
52+
* those files without knowing what the build directory is.
53+
*/
54+
StringMap extraFiles;
55+
56+
/**
57+
* A common case is to define an environment variable that points to
58+
* a file, which contains some contents.
59+
*
60+
* In base:
61+
* ```
62+
* export VAR=FILE_NAME
63+
* echo CONTENTS >FILE_NAME
64+
* ```
65+
*
66+
* This function assists in doing both parts, so the file name is
67+
* kept in sync.
68+
*/
69+
std::string & atFileEnvPair(std::string_view name, std::string fileName);
70+
71+
/**
72+
* Given a (resolved) derivation, its options, and the closure of
73+
* its inputs (which we can get since the derivation is resolved),
74+
* desugar the environment to create a `DesguaredEnv`.
75+
*
76+
* @todo drvOptions will go away as a separate argument when it is
77+
* just part of `Derivation`.
78+
*/
79+
static DesugaredEnv create(
80+
Store & store, const Derivation & drv, const DerivationOptions & drvOptions, const StorePathSet & inputPaths);
81+
};
82+
83+
} // namespace nix

src/libstore/include/nix/store/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ headers = [ config_pub_h ] + files(
1515
'build/derivation-builder.hh',
1616
'build/derivation-building-goal.hh',
1717
'build/derivation-building-misc.hh',
18+
'build/derivation-env-desugar.hh',
1819
'build/derivation-goal.hh',
1920
'build/derivation-trampoline-goal.hh',
2021
'build/drv-output-substitution-goal.hh',

src/libstore/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ sources = files(
266266
'build-result.cc',
267267
'build/derivation-building-goal.cc',
268268
'build/derivation-check.cc',
269+
'build/derivation-env-desugar.cc',
269270
'build/derivation-goal.cc',
270271
'build/derivation-trampoline-goal.cc',
271272
'build/drv-output-substitution-goal.cc',

src/libstore/unix/build/derivation-builder.cc

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "nix/store/restricted-store.hh"
1818
#include "nix/store/user-lock.hh"
1919
#include "nix/store/globals.hh"
20+
#include "nix/store/build/derivation-env-desugar.hh"
2021

2122
#include <queue>
2223

@@ -992,19 +993,13 @@ void DerivationBuilderImpl::initEnv()
992993
/* Write the final environment. Note that this is intentionally
993994
*not* `drv.env`, because we've desugared things like like
994995
"passAFile", "expandReferencesGraph", structured attrs, etc. */
995-
for (const auto & [name, info] : finalEnv) {
996-
if (info.nameOfPassAsFile) {
997-
auto & fileName = *info.nameOfPassAsFile;
998-
writeBuilderFile(fileName, rewriteStrings(info.value, inputRewrites));
999-
env[name] = tmpDirInSandbox() + "/" + fileName;
1000-
} else {
1001-
env[name] = info.value;
1002-
}
996+
for (const auto & [name, info] : desugaredEnv.variables) {
997+
env[name] = info.prependBuildDirectory ? tmpDirInSandbox() + "/" + info.value : info.value;
1003998
}
1004999

10051000
/* Add extra files, similar to `finalEnv` */
1006-
for (const auto & [fileName, value] : extraFiles) {
1007-
writeBuilderFile(fileName, value);
1001+
for (const auto & [fileName, value] : desugaredEnv.extraFiles) {
1002+
writeBuilderFile(fileName, rewriteStrings(value, inputRewrites));
10081003
}
10091004

10101005
/* For convenience, set an environment pointing to the top build

0 commit comments

Comments
 (0)