aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/build/local-derivation-goal.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore/build/local-derivation-goal.cc')
-rw-r--r--src/libstore/build/local-derivation-goal.cc118
1 files changed, 68 insertions, 50 deletions
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index 4c91fa4fb..3ac9c20f9 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -14,6 +14,7 @@
#include "worker-protocol.hh"
#include "topo-sort.hh"
#include "callback.hh"
+#include "json-utils.hh"
#include <regex>
#include <queue>
@@ -56,8 +57,6 @@
#include <pwd.h>
#include <grp.h>
-#include <nlohmann/json.hpp>
-
namespace nix {
void handleDiffHook(
@@ -482,7 +481,7 @@ void LocalDerivationGoal::startBuilder()
temporary build directory. The text files have the format used
by `nix-store --register-validity'. However, the deriver
fields are left empty. */
- auto s = get(drv->env, "exportReferencesGraph").value_or("");
+ auto s = getOr(drv->env, "exportReferencesGraph", "");
Strings ss = tokenizeString<Strings>(s);
if (ss.size() % 2 != 0)
throw BuildError("odd number of tokens in 'exportReferencesGraph': '%1%'", s);
@@ -989,7 +988,7 @@ void LocalDerivationGoal::initTmpDir() {
there is no size constraint). */
if (!parsedDrv->getStructuredAttrs()) {
- StringSet passAsFile = tokenizeString<StringSet>(get(drv->env, "passAsFile").value_or(""));
+ StringSet passAsFile = tokenizeString<StringSet>(getOr(drv->env, "passAsFile", ""));
for (auto & i : drv->env) {
if (passAsFile.find(i.first) == passAsFile.end()) {
env[i.first] = i.second;
@@ -2128,12 +2127,22 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
std::map<std::string, std::variant<AlreadyRegistered, PerhapsNeedToRegister>> outputReferencesIfUnregistered;
std::map<std::string, struct stat> outputStats;
for (auto & [outputName, _] : drv->outputs) {
- auto actualPath = toRealPathChroot(worker.store.printStorePath(scratchOutputs.at(outputName)));
+ auto scratchOutput = get(scratchOutputs, outputName);
+ if (!scratchOutput)
+ throw BuildError(
+ "builder for '%s' has no scratch output for '%s'",
+ worker.store.printStorePath(drvPath), outputName);
+ auto actualPath = toRealPathChroot(worker.store.printStorePath(*scratchOutput));
outputsToSort.insert(outputName);
/* Updated wanted info to remove the outputs we definitely don't need to register */
- auto & initialInfo = initialOutputs.at(outputName);
+ auto initialOutput = get(initialOutputs, outputName);
+ if (!initialOutput)
+ throw BuildError(
+ "builder for '%s' has no initial output for '%s'",
+ worker.store.printStorePath(drvPath), outputName);
+ auto & initialInfo = *initialOutput;
/* Don't register if already valid, and not checking */
initialInfo.wanted = buildMode == bmCheck
@@ -2185,6 +2194,11 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
auto sortedOutputNames = topoSort(outputsToSort,
{[&](const std::string & name) {
+ auto orifu = get(outputReferencesIfUnregistered, name);
+ if (!orifu)
+ throw BuildError(
+ "no output reference for '%s' in build of '%s'",
+ name, worker.store.printStorePath(drvPath));
return std::visit(overloaded {
/* Since we'll use the already installed versions of these, we
can treat them as leaves and ignore any references they
@@ -2199,7 +2213,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
referencedOutputs.insert(o);
return referencedOutputs;
},
- }, outputReferencesIfUnregistered.at(name));
+ }, *orifu);
}},
{[&](const std::string & path, const std::string & parent) {
// TODO with more -vvvv also show the temporary paths for manual inspection.
@@ -2213,9 +2227,10 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
OutputPathMap finalOutputs;
for (auto & outputName : sortedOutputNames) {
- auto output = drv->outputs.at(outputName);
- auto & scratchPath = scratchOutputs.at(outputName);
- auto actualPath = toRealPathChroot(worker.store.printStorePath(scratchPath));
+ auto output = get(drv->outputs, outputName);
+ auto scratchPath = get(scratchOutputs, outputName);
+ assert(output && scratchPath);
+ auto actualPath = toRealPathChroot(worker.store.printStorePath(*scratchPath));
auto finish = [&](StorePath finalStorePath) {
/* Store the final path */
@@ -2223,10 +2238,13 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
/* The rewrite rule will be used in downstream outputs that refer to
use. This is why the topological sort is essential to do first
before this for loop. */
- if (scratchPath != finalStorePath)
- outputRewrites[std::string { scratchPath.hashPart() }] = std::string { finalStorePath.hashPart() };
+ if (*scratchPath != finalStorePath)
+ outputRewrites[std::string { scratchPath->hashPart() }] = std::string { finalStorePath.hashPart() };
};
+ auto orifu = get(outputReferencesIfUnregistered, outputName);
+ assert(orifu);
+
std::optional<StorePathSet> referencesOpt = std::visit(overloaded {
[&](const AlreadyRegistered & skippedFinalPath) -> std::optional<StorePathSet> {
finish(skippedFinalPath.path);
@@ -2235,7 +2253,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
[&](const PerhapsNeedToRegister & r) -> std::optional<StorePathSet> {
return r.refs;
},
- }, outputReferencesIfUnregistered.at(outputName));
+ }, *orifu);
if (!referencesOpt)
continue;
@@ -2268,25 +2286,29 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
for (auto & r : references) {
auto name = r.name();
auto origHash = std::string { r.hashPart() };
- if (r == scratchPath)
+ if (r == *scratchPath) {
res.first = true;
- else if (outputRewrites.count(origHash) == 0)
- res.second.insert(r);
- else {
- std::string newRef = outputRewrites.at(origHash);
+ } else if (auto outputRewrite = get(outputRewrites, origHash)) {
+ std::string newRef = *outputRewrite;
newRef += '-';
newRef += name;
res.second.insert(StorePath { newRef });
+ } else {
+ res.second.insert(r);
}
}
return res;
};
auto newInfoFromCA = [&](const DerivationOutput::CAFloating outputHash) -> ValidPathInfo {
- auto & st = outputStats.at(outputName);
+ auto st = get(outputStats, outputName);
+ if (!st)
+ throw BuildError(
+ "output path %1% without valid stats info",
+ actualPath);
if (outputHash.method == FileIngestionMethod::Flat) {
/* The output path should be a regular file without execute permission. */
- if (!S_ISREG(st.st_mode) || (st.st_mode & S_IXUSR) != 0)
+ if (!S_ISREG(st->st_mode) || (st->st_mode & S_IXUSR) != 0)
throw BuildError(
"output path '%1%' should be a non-executable regular file "
"since recursive hashing is not enabled (outputHashMode=flat)",
@@ -2294,7 +2316,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
}
rewriteOutput();
/* FIXME optimize and deduplicate with addToStore */
- std::string oldHashPart { scratchPath.hashPart() };
+ std::string oldHashPart { scratchPath->hashPart() };
HashModuloSink caSink { outputHash.hashType, oldHashPart };
switch (outputHash.method) {
case FileIngestionMethod::Recursive:
@@ -2313,7 +2335,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
outputPathName(drv->name, outputName),
refs.second,
refs.first);
- if (scratchPath != finalPath) {
+ if (*scratchPath != finalPath) {
// Also rewrite the output path
auto source = sinkToSource([&](Sink & nextSink) {
StringSink sink;
@@ -2354,9 +2376,9 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
auto requiredFinalPath = output.path;
/* Preemptively add rewrite rule for final hash, as that is
what the NAR hash will use rather than normalized-self references */
- if (scratchPath != requiredFinalPath)
+ if (*scratchPath != requiredFinalPath)
outputRewrites.insert_or_assign(
- std::string { scratchPath.hashPart() },
+ std::string { scratchPath->hashPart() },
std::string { requiredFinalPath.hashPart() });
rewriteOutput();
auto narHashAndSize = hashPath(htSHA256, actualPath);
@@ -2409,7 +2431,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
});
},
- }, output.raw());
+ }, output->raw());
/* FIXME: set proper permissions in restorePath() so
we don't have to do another traversal. */
@@ -2425,7 +2447,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
derivations. */
PathLocks dynamicOutputLock;
dynamicOutputLock.setDeletion(true);
- auto optFixedPath = output.path(worker.store, drv->name, outputName);
+ auto optFixedPath = output->path(worker.store, drv->name, outputName);
if (!optFixedPath ||
worker.store.printStorePath(*optFixedPath) != finalDestPath)
{
@@ -2491,11 +2513,10 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
/* For debugging, print out the referenced and unreferenced paths. */
for (auto & i : inputPaths) {
- auto j = references.find(i);
- if (j == references.end())
- debug("unreferenced input: '%1%'", worker.store.printStorePath(i));
- else
+ if (references.count(i))
debug("referenced input: '%1%'", worker.store.printStorePath(i));
+ else
+ debug("unreferenced input: '%1%'", worker.store.printStorePath(i));
}
if (curRound == nrRounds) {
@@ -2612,9 +2633,11 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
DrvOutputs builtOutputs;
for (auto & [outputName, newInfo] : infos) {
+ auto oldinfo = get(initialOutputs, outputName);
+ assert(oldinfo);
auto thisRealisation = Realisation {
.id = DrvOutput {
- initialOutputs.at(outputName).outputHash,
+ oldinfo->outputHash,
outputName
},
.outPath = newInfo.path
@@ -2710,9 +2733,10 @@ void LocalDerivationGoal::checkOutputs(const std::map<std::string, ValidPathInfo
for (auto & i : *value) {
if (worker.store.isStorePath(i))
spec.insert(worker.store.parseStorePath(i));
- else if (outputs.count(i))
- spec.insert(outputs.at(i).path);
- else throw BuildError("derivation contains an illegal reference specifier '%s'", i);
+ else if (auto output = get(outputs, i))
+ spec.insert(output->path);
+ else
+ throw BuildError("derivation contains an illegal reference specifier '%s'", i);
}
auto used = recursive
@@ -2751,24 +2775,18 @@ void LocalDerivationGoal::checkOutputs(const std::map<std::string, ValidPathInfo
};
if (auto structuredAttrs = parsedDrv->getStructuredAttrs()) {
- auto outputChecks = structuredAttrs->find("outputChecks");
- if (outputChecks != structuredAttrs->end()) {
- auto output = outputChecks->find(outputName);
-
- if (output != outputChecks->end()) {
+ if (auto outputChecks = get(*structuredAttrs, "outputChecks")) {
+ if (auto output = get(*outputChecks, outputName)) {
Checks checks;
- auto maxSize = output->find("maxSize");
- if (maxSize != output->end())
+ if (auto maxSize = get(*output, "maxSize"))
checks.maxSize = maxSize->get<uint64_t>();
- auto maxClosureSize = output->find("maxClosureSize");
- if (maxClosureSize != output->end())
+ if (auto maxClosureSize = get(*output, "maxClosureSize"))
checks.maxClosureSize = maxClosureSize->get<uint64_t>();
- auto get = [&](const std::string & name) -> std::optional<Strings> {
- auto i = output->find(name);
- if (i != output->end()) {
+ auto get_ = [&](const std::string & name) -> std::optional<Strings> {
+ if (auto i = get(*output, name)) {
Strings res;
for (auto j = i->begin(); j != i->end(); ++j) {
if (!j->is_string())
@@ -2781,10 +2799,10 @@ void LocalDerivationGoal::checkOutputs(const std::map<std::string, ValidPathInfo
return {};
};
- checks.allowedReferences = get("allowedReferences");
- checks.allowedRequisites = get("allowedRequisites");
- checks.disallowedReferences = get("disallowedReferences");
- checks.disallowedRequisites = get("disallowedRequisites");
+ checks.allowedReferences = get_("allowedReferences");
+ checks.allowedRequisites = get_("allowedRequisites");
+ checks.disallowedReferences = get_("disallowedReferences");
+ checks.disallowedRequisites = get_("disallowedRequisites");
applyChecks(checks);
}