From 55dbb7f1ccc0e991df6b09af0a16ce9246ac3f19 Mon Sep 17 00:00:00 2001 From: regnat Date: Mon, 13 Dec 2021 16:56:44 +0100 Subject: [PATCH 1/2] More properly track the status of CA builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the build of unresolved derivations return the same status as the resolved one, except in the case of an `AlreadyValid` in which case it will return `ResolvesToAlreadyValid` to mean that the outputs of the unresolved derivation weren’t known, but the resolved one is. --- src/libstore/build/derivation-goal.cc | 26 +++++++++++++++++--------- src/libstore/build/derivation-goal.hh | 4 ++-- src/libstore/store-api.hh | 3 ++- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index 60945403e..a713d7222 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -464,7 +464,6 @@ void DerivationGoal::inputsRealised() Derivation drvResolved { *std::move(attempt) }; auto pathResolved = writeDerivation(worker.store, drvResolved); - resolvedDrv = drvResolved; auto msg = fmt("Resolved derivation: '%s' -> '%s'", worker.store.printStorePath(drvPath), @@ -475,9 +474,9 @@ void DerivationGoal::inputsRealised() worker.store.printStorePath(pathResolved), }); - auto resolvedGoal = worker.makeDerivationGoal( + resolvedDrvGoal = worker.makeDerivationGoal( pathResolved, wantedOutputs, buildMode); - addWaitee(resolvedGoal); + addWaitee(resolvedDrvGoal); state = &DerivationGoal::resolvedFinished; return; @@ -938,16 +937,17 @@ void DerivationGoal::buildDone() } void DerivationGoal::resolvedFinished() { - assert(resolvedDrv); + assert(resolvedDrvGoal); + auto resolvedDrv = *resolvedDrvGoal->drv; - auto resolvedHashes = staticOutputHashes(worker.store, *resolvedDrv); + auto resolvedHashes = staticOutputHashes(worker.store, resolvedDrv); StorePathSet outputPaths; // `wantedOutputs` might be empty, which means “all the outputs” auto realWantedOutputs = wantedOutputs; if (realWantedOutputs.empty()) - realWantedOutputs = resolvedDrv->outputNames(); + realWantedOutputs = resolvedDrv.outputNames(); for (auto & wantedOutput : realWantedOutputs) { assert(initialOutputs.count(wantedOutput) != 0); @@ -979,9 +979,17 @@ void DerivationGoal::resolvedFinished() { outputPaths ); - // This is potentially a bit fishy in terms of error reporting. Not sure - // how to do it in a cleaner way - amDone(nrFailed == 0 ? ecSuccess : ecFailed, ex); + auto status = [&]() { + auto resolvedResult = resolvedDrvGoal->getResult(); + switch (resolvedResult.status) { + case BuildResult::AlreadyValid: + return BuildResult::ResolvesToAlreadyValid; + default: + return resolvedResult.status; + } + }(); + + done(status); } HookReply DerivationGoal::tryBuildHook() diff --git a/src/libstore/build/derivation-goal.hh b/src/libstore/build/derivation-goal.hh index 704b77caf..e112542c7 100644 --- a/src/libstore/build/derivation-goal.hh +++ b/src/libstore/build/derivation-goal.hh @@ -50,8 +50,8 @@ struct DerivationGoal : public Goal /* The path of the derivation. */ StorePath drvPath; - /* The path of the corresponding resolved derivation */ - std::optional resolvedDrv; + /* The goal for the corresponding resolved derivation */ + std::shared_ptr resolvedDrvGoal; /* The specific outputs that we need to build. Empty means all of them. */ diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index aa44651d4..3a385b293 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -151,6 +151,7 @@ struct BuildResult DependencyFailed, LogLimitExceeded, NotDeterministic, + ResolvesToAlreadyValid, } status = MiscFailure; std::string errorMsg; @@ -170,7 +171,7 @@ struct BuildResult time_t startTime = 0, stopTime = 0; bool success() { - return status == Built || status == Substituted || status == AlreadyValid; + return status == Built || status == Substituted || status == AlreadyValid || status == ResolvesToAlreadyValid; } }; From 2eec2f765a86b8954f3a74ff148bc70a2d32be27 Mon Sep 17 00:00:00 2001 From: regnat Date: Mon, 13 Dec 2021 16:58:43 +0100 Subject: [PATCH 2/2] Add a crude tracing mechansim for the build results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a `_NIX_TRACE_BUILT_OUTPUTS` environment variable that can be set to a filename in which the result of each build will be logged. This is intentionally crude and undocumented as it’s only meant to be a temporary thing to assess the usefulness of CA derivations. Any other use would need a cleaner re-implementation first. --- src/libstore/build/derivation-goal.cc | 8 ++++++++ src/libstore/store-api.hh | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index a713d7222..c6ab5c3d1 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -1337,6 +1338,13 @@ void DerivationGoal::done(BuildResult::Status status, std::optional ex) } worker.updateProgress(); + + auto traceBuiltOutputsFile = getEnv("_NIX_TRACE_BUILT_OUTPUTS").value_or(""); + if (traceBuiltOutputsFile != "") { + std::fstream fs; + fs.open(traceBuiltOutputsFile, std::fstream::out); + fs << worker.store.printStorePath(drvPath) << "\t" << result.toString() << std::endl; + } } diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 3a385b293..3dd446f23 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -155,6 +155,29 @@ struct BuildResult } status = MiscFailure; std::string errorMsg; + std::string toString() const { + auto strStatus = [&]() { + switch (status) { + case Built: return "Built"; + case Substituted: return "Substituted"; + case AlreadyValid: return "AlreadyValid"; + case PermanentFailure: return "PermanentFailure"; + case InputRejected: return "InputRejected"; + case OutputRejected: return "OutputRejected"; + case TransientFailure: return "TransientFailure"; + case CachedFailure: return "CachedFailure"; + case TimedOut: return "TimedOut"; + case MiscFailure: return "MiscFailure"; + case DependencyFailed: return "DependencyFailed"; + case LogLimitExceeded: return "LogLimitExceeded"; + case NotDeterministic: return "NotDeterministic"; + case ResolvesToAlreadyValid: return "ResolvesToAlreadyValid"; + default: return "Unknown"; + }; + }(); + return strStatus + ((errorMsg == "") ? "" : " : " + errorMsg); + } + /* How many times this build was performed. */ unsigned int timesBuilt = 0;