mirror of
https://github.com/NixOS/nix.git
synced 2025-11-08 19:46:02 +01:00
Simplify handling of statuses for build errors
Instead of passing them around separately, or doing finicky logic in a try-catch block to recover them, just make `BuildError` always contain a status, and make it the thrower's responsibility to set it. This is much more simple and explicit. Once that change is done, split the `done` functions of `DerivationGoal` and `DerivationBuildingGoal` into separate success and failure functions, which ends up being easier to understand and hardly any duplication. Also, change the handling of failures in resolved cases to use `BuildResult::DependencyFailed` and a new message. This is because the underlying derivation will also get its message printed --- which is good, because in general the resolved derivation is not unique. One dyn drv test had to be updated, but CA (and dyn drv) is experimental, so I do not mind. Finally, delete `SubstError` because it is unused.
This commit is contained in:
parent
0590b13156
commit
169033001d
16 changed files with 153 additions and 92 deletions
|
|
@ -118,7 +118,7 @@ void DerivationBuildingGoal::timedOut(Error && ex)
|
|||
killChild();
|
||||
// We're not inside a coroutine, hence we can't use co_return here.
|
||||
// Thus we ignore the return value.
|
||||
[[maybe_unused]] Done _ = done(BuildResult::TimedOut, {}, std::move(ex));
|
||||
[[maybe_unused]] Done _ = doneFailure({BuildResult::TimedOut, std::move(ex)});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -258,7 +258,7 @@ Goal::Co DerivationBuildingGoal::gaveUpOnSubstitution()
|
|||
nrFailed,
|
||||
nrFailed == 1 ? "dependency" : "dependencies");
|
||||
msg += showKnownOutputs(worker.store, *drv);
|
||||
co_return done(BuildResult::DependencyFailed, {}, Error(msg));
|
||||
co_return doneFailure(BuildError(BuildResult::DependencyFailed, msg));
|
||||
}
|
||||
|
||||
/* Gather information necessary for computing the closure and/or
|
||||
|
|
@ -359,9 +359,9 @@ Goal::Co DerivationBuildingGoal::gaveUpOnSubstitution()
|
|||
|
||||
auto resolvedResult = resolvedDrvGoal->buildResult;
|
||||
|
||||
SingleDrvOutputs builtOutputs;
|
||||
|
||||
if (resolvedResult.success()) {
|
||||
SingleDrvOutputs builtOutputs;
|
||||
|
||||
auto resolvedHashes = staticOutputHashes(worker.store, drvResolved);
|
||||
|
||||
StorePathSet outputPaths;
|
||||
|
|
@ -411,13 +411,19 @@ Goal::Co DerivationBuildingGoal::gaveUpOnSubstitution()
|
|||
}
|
||||
|
||||
runPostBuildHook(worker.store, *logger, drvPath, outputPaths);
|
||||
|
||||
auto status = resolvedResult.status;
|
||||
if (status == BuildResult::AlreadyValid)
|
||||
status = BuildResult::ResolvesToAlreadyValid;
|
||||
|
||||
co_return doneSuccess(status, std::move(builtOutputs));
|
||||
} else {
|
||||
co_return doneFailure({
|
||||
BuildResult::DependencyFailed,
|
||||
"build of resolved derivation '%s' failed",
|
||||
worker.store.printStorePath(pathResolved),
|
||||
});
|
||||
}
|
||||
|
||||
auto status = resolvedResult.status;
|
||||
if (status == BuildResult::AlreadyValid)
|
||||
status = BuildResult::ResolvesToAlreadyValid;
|
||||
|
||||
co_return done(status, std::move(builtOutputs));
|
||||
}
|
||||
|
||||
/* If we get this far, we know no dynamic drvs inputs */
|
||||
|
|
@ -542,7 +548,7 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
|
|||
debug("skipping build of derivation '%s', someone beat us to it", worker.store.printStorePath(drvPath));
|
||||
outputLocks.setDeletion(true);
|
||||
outputLocks.unlock();
|
||||
co_return done(BuildResult::AlreadyValid, std::move(validOutputs));
|
||||
co_return doneSuccess(BuildResult::AlreadyValid, std::move(validOutputs));
|
||||
}
|
||||
|
||||
/* If any of the outputs already exist but are not valid, delete
|
||||
|
|
@ -752,7 +758,7 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
|
|||
} catch (BuildError & e) {
|
||||
outputLocks.unlock();
|
||||
worker.permanentFailure = true;
|
||||
co_return done(BuildResult::InputRejected, {}, std::move(e));
|
||||
co_return doneFailure(std::move(e));
|
||||
}
|
||||
|
||||
/* If we have to wait and retry (see below), then `builder` will
|
||||
|
|
@ -800,7 +806,7 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
|
|||
builder.reset();
|
||||
outputLocks.unlock();
|
||||
worker.permanentFailure = true;
|
||||
co_return done(BuildResult::InputRejected, {}, std::move(e));
|
||||
co_return doneFailure(std::move(e)); // InputRejected
|
||||
}
|
||||
|
||||
started();
|
||||
|
|
@ -812,7 +818,7 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
|
|||
// N.B. cannot use `std::visit` with co-routine return
|
||||
if (auto * ste = std::get_if<0>(&res)) {
|
||||
outputLocks.unlock();
|
||||
co_return done(std::move(ste->first), {}, std::move(ste->second));
|
||||
co_return doneFailure(std::move(*ste));
|
||||
} else if (auto * builtOutputs = std::get_if<1>(&res)) {
|
||||
StorePathSet outputPaths;
|
||||
for (auto & [_, output] : *builtOutputs)
|
||||
|
|
@ -825,7 +831,7 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
|
|||
(unlinked) lock files. */
|
||||
outputLocks.setDeletion(true);
|
||||
outputLocks.unlock();
|
||||
co_return done(BuildResult::Built, std::move(*builtOutputs));
|
||||
co_return doneSuccess(BuildResult::Built, std::move(*builtOutputs));
|
||||
} else {
|
||||
unreachable();
|
||||
}
|
||||
|
|
@ -970,7 +976,7 @@ Goal::Co DerivationBuildingGoal::hookDone()
|
|||
|
||||
/* TODO (once again) support fine-grained error codes, see issue #12641. */
|
||||
|
||||
co_return done(BuildResult::MiscFailure, {}, BuildError(msg));
|
||||
co_return doneFailure(BuildError{BuildResult::MiscFailure, msg});
|
||||
}
|
||||
|
||||
/* Compute the FS closure of the outputs and register them as
|
||||
|
|
@ -997,7 +1003,7 @@ Goal::Co DerivationBuildingGoal::hookDone()
|
|||
outputLocks.setDeletion(true);
|
||||
outputLocks.unlock();
|
||||
|
||||
co_return done(BuildResult::Built, std::move(builtOutputs));
|
||||
co_return doneSuccess(BuildResult::Built, std::move(builtOutputs));
|
||||
}
|
||||
|
||||
HookReply DerivationBuildingGoal::tryBuildHook()
|
||||
|
|
@ -1179,10 +1185,11 @@ void DerivationBuildingGoal::handleChildOutput(Descriptor fd, std::string_view d
|
|||
killChild();
|
||||
// We're not inside a coroutine, hence we can't use co_return here.
|
||||
// Thus we ignore the return value.
|
||||
[[maybe_unused]] Done _ = done(
|
||||
[[maybe_unused]] Done _ = doneFailure(BuildError(
|
||||
BuildResult::LogLimitExceeded,
|
||||
{},
|
||||
Error("%s killed after writing more than %d bytes of log output", getName(), settings.maxLogSize));
|
||||
"%s killed after writing more than %d bytes of log output",
|
||||
getName(),
|
||||
settings.maxLogSize));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1343,13 +1350,27 @@ SingleDrvOutputs DerivationBuildingGoal::assertPathValidity()
|
|||
return validOutputs;
|
||||
}
|
||||
|
||||
Goal::Done
|
||||
DerivationBuildingGoal::done(BuildResult::Status status, SingleDrvOutputs builtOutputs, std::optional<Error> ex)
|
||||
Goal::Done DerivationBuildingGoal::doneSuccess(BuildResult::Status status, SingleDrvOutputs builtOutputs)
|
||||
{
|
||||
outputLocks.unlock();
|
||||
buildResult.status = status;
|
||||
if (ex)
|
||||
buildResult.errorMsg = fmt("%s", Uncolored(ex->info().msg));
|
||||
|
||||
assert(buildResult.success());
|
||||
|
||||
mcRunningBuilds.reset();
|
||||
|
||||
buildResult.builtOutputs = std::move(builtOutputs);
|
||||
if (status == BuildResult::Built)
|
||||
worker.doneBuilds++;
|
||||
|
||||
worker.updateProgress();
|
||||
|
||||
return amDone(ecSuccess, std::nullopt);
|
||||
}
|
||||
|
||||
Goal::Done DerivationBuildingGoal::doneFailure(BuildError ex)
|
||||
{
|
||||
buildResult.status = ex.status;
|
||||
buildResult.errorMsg = fmt("%s", Uncolored(ex.info().msg));
|
||||
if (buildResult.status == BuildResult::TimedOut)
|
||||
worker.timedOut = true;
|
||||
if (buildResult.status == BuildResult::PermanentFailure)
|
||||
|
|
@ -1357,18 +1378,12 @@ DerivationBuildingGoal::done(BuildResult::Status status, SingleDrvOutputs builtO
|
|||
|
||||
mcRunningBuilds.reset();
|
||||
|
||||
if (buildResult.success()) {
|
||||
buildResult.builtOutputs = std::move(builtOutputs);
|
||||
if (status == BuildResult::Built)
|
||||
worker.doneBuilds++;
|
||||
} else {
|
||||
if (status != BuildResult::DependencyFailed)
|
||||
worker.failedBuilds++;
|
||||
}
|
||||
if (ex.status != BuildResult::DependencyFailed)
|
||||
worker.failedBuilds++;
|
||||
|
||||
worker.updateProgress();
|
||||
|
||||
return amDone(buildResult.success() ? ecSuccess : ecFailed, std::move(ex));
|
||||
return amDone(ecFailed, {std::move(ex)});
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <queue>
|
||||
|
||||
#include "nix/store/store-api.hh"
|
||||
#include "nix/store/build-result.hh"
|
||||
|
||||
#include "derivation-check.hh"
|
||||
|
||||
|
|
@ -54,6 +55,7 @@ void checkOutputs(
|
|||
auto applyChecks = [&](const DerivationOptions::OutputChecks & checks) {
|
||||
if (checks.maxSize && info.narSize > *checks.maxSize)
|
||||
throw BuildError(
|
||||
BuildResult::OutputRejected,
|
||||
"path '%s' is too large at %d bytes; limit is %d bytes",
|
||||
store.printStorePath(info.path),
|
||||
info.narSize,
|
||||
|
|
@ -63,6 +65,7 @@ void checkOutputs(
|
|||
uint64_t closureSize = getClosure(info.path).second;
|
||||
if (closureSize > *checks.maxClosureSize)
|
||||
throw BuildError(
|
||||
BuildResult::OutputRejected,
|
||||
"closure of path '%s' is too large at %d bytes; limit is %d bytes",
|
||||
store.printStorePath(info.path),
|
||||
closureSize,
|
||||
|
|
@ -83,6 +86,7 @@ void checkOutputs(
|
|||
std::string outputsListing =
|
||||
concatMapStringsSep(", ", outputs, [](auto & o) { return o.first; });
|
||||
throw BuildError(
|
||||
BuildResult::OutputRejected,
|
||||
"derivation '%s' output check for '%s' contains an illegal reference specifier '%s',"
|
||||
" expected store path or output name (one of [%s])",
|
||||
store.printStorePath(drvPath),
|
||||
|
|
@ -115,6 +119,7 @@ void checkOutputs(
|
|||
badPathsStr += store.printStorePath(i);
|
||||
}
|
||||
throw BuildError(
|
||||
BuildResult::OutputRejected,
|
||||
"output '%s' is not allowed to refer to the following paths:%s",
|
||||
store.printStorePath(info.path),
|
||||
badPathsStr);
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ Goal::Co DerivationGoal::haveDerivation()
|
|||
|
||||
/* If they are all valid, then we're done. */
|
||||
if (checkResult && checkResult->second == PathStatus::Valid && buildMode == bmNormal) {
|
||||
co_return done(BuildResult::AlreadyValid, checkResult->first);
|
||||
co_return doneSuccess(BuildResult::AlreadyValid, checkResult->first);
|
||||
}
|
||||
|
||||
Goals waitees;
|
||||
|
|
@ -122,12 +122,10 @@ Goal::Co DerivationGoal::haveDerivation()
|
|||
assert(!drv->type().isImpure());
|
||||
|
||||
if (nrFailed > 0 && nrFailed > nrNoSubstituters && !settings.tryFallback) {
|
||||
co_return done(
|
||||
co_return doneFailure(BuildError(
|
||||
BuildResult::TransientFailure,
|
||||
{},
|
||||
Error(
|
||||
"some substitutes for the outputs of derivation '%s' failed (usually happens due to networking issues); try '--fallback' to build derivation from source ",
|
||||
worker.store.printStorePath(drvPath)));
|
||||
"some substitutes for the outputs of derivation '%s' failed (usually happens due to networking issues); try '--fallback' to build derivation from source ",
|
||||
worker.store.printStorePath(drvPath)));
|
||||
}
|
||||
|
||||
nrFailed = nrNoSubstituters = 0;
|
||||
|
|
@ -137,7 +135,7 @@ Goal::Co DerivationGoal::haveDerivation()
|
|||
bool allValid = checkResult && checkResult->second == PathStatus::Valid;
|
||||
|
||||
if (buildMode == bmNormal && allValid) {
|
||||
co_return done(BuildResult::Substituted, checkResult->first);
|
||||
co_return doneSuccess(BuildResult::Substituted, checkResult->first);
|
||||
}
|
||||
if (buildMode == bmRepair && allValid) {
|
||||
co_return repairClosure();
|
||||
|
|
@ -281,7 +279,7 @@ Goal::Co DerivationGoal::repairClosure()
|
|||
"some paths in the output closure of derivation '%s' could not be repaired",
|
||||
worker.store.printStorePath(drvPath));
|
||||
}
|
||||
co_return done(BuildResult::AlreadyValid, assertPathValidity());
|
||||
co_return doneSuccess(BuildResult::AlreadyValid, assertPathValidity());
|
||||
}
|
||||
|
||||
std::optional<std::pair<Realisation, PathStatus>> DerivationGoal::checkPathValidity()
|
||||
|
|
@ -339,12 +337,27 @@ Realisation DerivationGoal::assertPathValidity()
|
|||
return checkResult->first;
|
||||
}
|
||||
|
||||
Goal::Done
|
||||
DerivationGoal::done(BuildResult::Status status, std::optional<Realisation> builtOutput, std::optional<Error> ex)
|
||||
Goal::Done DerivationGoal::doneSuccess(BuildResult::Status status, Realisation builtOutput)
|
||||
{
|
||||
buildResult.status = status;
|
||||
if (ex)
|
||||
buildResult.errorMsg = fmt("%s", Uncolored(ex->info().msg));
|
||||
|
||||
assert(buildResult.success());
|
||||
|
||||
mcExpectedBuilds.reset();
|
||||
|
||||
buildResult.builtOutputs = {{wantedOutput, std::move(builtOutput)}};
|
||||
if (status == BuildResult::Built)
|
||||
worker.doneBuilds++;
|
||||
|
||||
worker.updateProgress();
|
||||
|
||||
return amDone(ecSuccess, std::nullopt);
|
||||
}
|
||||
|
||||
Goal::Done DerivationGoal::doneFailure(BuildError ex)
|
||||
{
|
||||
buildResult.status = ex.status;
|
||||
buildResult.errorMsg = fmt("%s", Uncolored(ex.info().msg));
|
||||
if (buildResult.status == BuildResult::TimedOut)
|
||||
worker.timedOut = true;
|
||||
if (buildResult.status == BuildResult::PermanentFailure)
|
||||
|
|
@ -352,19 +365,12 @@ DerivationGoal::done(BuildResult::Status status, std::optional<Realisation> buil
|
|||
|
||||
mcExpectedBuilds.reset();
|
||||
|
||||
if (buildResult.success()) {
|
||||
assert(builtOutput);
|
||||
buildResult.builtOutputs = {{wantedOutput, std::move(*builtOutput)}};
|
||||
if (status == BuildResult::Built)
|
||||
worker.doneBuilds++;
|
||||
} else {
|
||||
if (status != BuildResult::DependencyFailed)
|
||||
worker.failedBuilds++;
|
||||
}
|
||||
if (ex.status != BuildResult::DependencyFailed)
|
||||
worker.failedBuilds++;
|
||||
|
||||
worker.updateProgress();
|
||||
|
||||
return amDone(buildResult.success() ? ecSuccess : ecFailed, std::move(ex));
|
||||
return amDone(ecFailed, {std::move(ex)});
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
|||
|
|
@ -265,7 +265,8 @@ DerivationOptions::getParsedExportReferencesGraph(const StoreDirConfig & store)
|
|||
StorePathSet storePaths;
|
||||
for (auto & storePathS : ss) {
|
||||
if (!store.isInStore(storePathS))
|
||||
throw BuildError("'exportReferencesGraph' contains a non-store path '%1%'", storePathS);
|
||||
throw BuildError(
|
||||
BuildResult::InputRejected, "'exportReferencesGraph' contains a non-store path '%1%'", storePathS);
|
||||
storePaths.insert(store.toStorePath(storePathS).first);
|
||||
}
|
||||
res.insert_or_assign(fileName, storePaths);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "nix/store/realisation.hh"
|
||||
#include "nix/store/derived-path.hh"
|
||||
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
|
||||
#include "nix/store/derived-path.hh"
|
||||
#include "nix/store/realisation.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct BuildResult
|
||||
|
|
@ -90,6 +90,26 @@ struct BuildResult
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* denotes a permanent build failure
|
||||
*/
|
||||
struct BuildError : public Error
|
||||
{
|
||||
BuildResult::Status status;
|
||||
|
||||
BuildError(BuildResult::Status status, BuildError && error)
|
||||
: Error{std::move(error)}
|
||||
, status{status}
|
||||
{
|
||||
}
|
||||
|
||||
BuildError(BuildResult::Status status, auto &&... args)
|
||||
: Error{args...}
|
||||
, status{status}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A `BuildResult` together with its "primary key".
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ struct DerivationBuilder : RestrictionContext
|
|||
* more information. The second case indicates success, and
|
||||
* realisations for each output of the derivation are returned.
|
||||
*/
|
||||
virtual std::variant<std::pair<BuildResult::Status, Error>, SingleDrvOutputs> unprepareBuild() = 0;
|
||||
virtual std::variant<BuildError, SingleDrvOutputs> unprepareBuild() = 0;
|
||||
|
||||
/**
|
||||
* Stop the in-process nix daemon thread.
|
||||
|
|
|
|||
|
|
@ -170,7 +170,9 @@ struct DerivationBuildingGoal : public Goal
|
|||
|
||||
void started();
|
||||
|
||||
Done done(BuildResult::Status status, SingleDrvOutputs builtOutputs = {}, std::optional<Error> ex = {});
|
||||
Done doneSuccess(BuildResult::Status status, SingleDrvOutputs builtOutputs);
|
||||
|
||||
Done doneFailure(BuildError ex);
|
||||
|
||||
void appendLogTailErrorMsg(std::string & msg);
|
||||
|
||||
|
|
|
|||
|
|
@ -99,13 +99,9 @@ private:
|
|||
|
||||
Co repairClosure();
|
||||
|
||||
/**
|
||||
* @param builtOutput Must be set if `status` is successful.
|
||||
*/
|
||||
Done done(
|
||||
BuildResult::Status status,
|
||||
std::optional<Realisation> builtOutput = std::nullopt,
|
||||
std::optional<Error> ex = {});
|
||||
Done doneSuccess(BuildResult::Status status, Realisation builtOutput);
|
||||
|
||||
Done doneFailure(BuildError ex);
|
||||
};
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
|||
|
|
@ -24,11 +24,6 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
MakeError(SubstError, Error);
|
||||
/**
|
||||
* denotes a permanent build failure
|
||||
*/
|
||||
MakeError(BuildError, Error);
|
||||
MakeError(InvalidPath, Error);
|
||||
MakeError(Unsupported, Error);
|
||||
MakeError(SubstituteGone, Error);
|
||||
|
|
|
|||
|
|
@ -1002,7 +1002,10 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
|
|||
}},
|
||||
{[&](const StorePath & path, const StorePath & parent) {
|
||||
return BuildError(
|
||||
"cycle detected in the references of '%s' from '%s'", printStorePath(path), printStorePath(parent));
|
||||
BuildResult::OutputRejected,
|
||||
"cycle detected in the references of '%s' from '%s'",
|
||||
printStorePath(path),
|
||||
printStorePath(parent));
|
||||
}});
|
||||
|
||||
txn.commit();
|
||||
|
|
|
|||
|
|
@ -322,7 +322,10 @@ StorePaths Store::topoSortPaths(const StorePathSet & paths)
|
|||
}},
|
||||
{[&](const StorePath & path, const StorePath & parent) {
|
||||
return BuildError(
|
||||
"cycle detected in the references of '%s' from '%s'", printStorePath(path), printStorePath(parent));
|
||||
BuildResult::OutputRejected,
|
||||
"cycle detected in the references of '%s' from '%s'",
|
||||
printStorePath(path),
|
||||
printStorePath(parent));
|
||||
}});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ static void canonicalisePathMetaData_(
|
|||
(i.e. "touch $out/foo; ln $out/foo $out/bar"). */
|
||||
if (uidRange && (st.st_uid < uidRange->first || st.st_uid > uidRange->second)) {
|
||||
if (S_ISDIR(st.st_mode) || !inodesSeen.count(Inode(st.st_dev, st.st_ino)))
|
||||
throw BuildError("invalid ownership on file '%1%'", path);
|
||||
throw BuildError(BuildResult::OutputRejected, "invalid ownership on file '%1%'", path);
|
||||
mode_t mode = st.st_mode & ~S_IFMT;
|
||||
assert(
|
||||
S_ISLNK(st.st_mode)
|
||||
|
|
|
|||
|
|
@ -770,6 +770,7 @@ StorePathSet Store::exportReferences(const StorePathSet & storePaths, const Stor
|
|||
for (auto & storePath : storePaths) {
|
||||
if (!inputPaths.count(storePath))
|
||||
throw BuildError(
|
||||
BuildResult::InputRejected,
|
||||
"cannot export references of path '%s' because it is not in the input closure of the derivation",
|
||||
printStorePath(storePath));
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,13 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
MakeError(NotDeterministic, BuildError);
|
||||
struct NotDeterministic : BuildError
|
||||
{
|
||||
NotDeterministic(auto &&... args)
|
||||
: BuildError(BuildResult::NotDeterministic, args...)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This class represents the state for building locally.
|
||||
|
|
@ -185,7 +191,7 @@ public:
|
|||
|
||||
void startBuilder() override;
|
||||
|
||||
std::variant<std::pair<BuildResult::Status, Error>, SingleDrvOutputs> unprepareBuild() override;
|
||||
std::variant<BuildError, SingleDrvOutputs> unprepareBuild() override;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
@ -420,7 +426,7 @@ bool DerivationBuilderImpl::prepareBuild()
|
|||
return true;
|
||||
}
|
||||
|
||||
std::variant<std::pair<BuildResult::Status, Error>, SingleDrvOutputs> DerivationBuilderImpl::unprepareBuild()
|
||||
std::variant<BuildError, SingleDrvOutputs> DerivationBuilderImpl::unprepareBuild()
|
||||
{
|
||||
// FIXME: get rid of this, rely on RAII.
|
||||
Finally releaseBuildUser([&]() {
|
||||
|
|
@ -493,7 +499,10 @@ std::variant<std::pair<BuildResult::Status, Error>, SingleDrvOutputs> Derivation
|
|||
if (diskFull)
|
||||
msg += "\nnote: build failure may have been caused by lack of free disk space";
|
||||
|
||||
throw BuildError(msg);
|
||||
throw BuildError(
|
||||
!derivationType.isSandboxed() || diskFull ? BuildResult::TransientFailure
|
||||
: BuildResult::PermanentFailure,
|
||||
msg);
|
||||
}
|
||||
|
||||
/* Compute the FS closure of the outputs and register them as
|
||||
|
|
@ -509,12 +518,7 @@ std::variant<std::pair<BuildResult::Status, Error>, SingleDrvOutputs> Derivation
|
|||
return std::move(builtOutputs);
|
||||
|
||||
} catch (BuildError & e) {
|
||||
BuildResult::Status st = dynamic_cast<NotDeterministic *>(&e) ? BuildResult::NotDeterministic
|
||||
: statusOk(status) ? BuildResult::OutputRejected
|
||||
: !derivationType.isSandboxed() || diskFull ? BuildResult::TransientFailure
|
||||
: BuildResult::PermanentFailure;
|
||||
|
||||
return std::pair{std::move(st), std::move(e)};
|
||||
return std::move(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -682,7 +686,7 @@ void DerivationBuilderImpl::startBuilder()
|
|||
fmt("\nNote: run `%s` to run programs for x86_64-darwin",
|
||||
Magenta("/usr/sbin/softwareupdate --install-rosetta && launchctl stop org.nixos.nix-daemon"));
|
||||
|
||||
throw BuildError(msg);
|
||||
throw BuildError(BuildResult::InputRejected, msg);
|
||||
}
|
||||
|
||||
auto buildDir = store.config->getBuildDir();
|
||||
|
|
@ -1378,6 +1382,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
|||
auto optSt = maybeLstat(actualPath.c_str());
|
||||
if (!optSt)
|
||||
throw BuildError(
|
||||
BuildResult::OutputRejected,
|
||||
"builder for '%s' failed to produce output path for output '%s' at '%s'",
|
||||
store.printStorePath(drvPath),
|
||||
outputName,
|
||||
|
|
@ -1392,6 +1397,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
|||
if ((!S_ISLNK(st.st_mode) && (st.st_mode & (S_IWGRP | S_IWOTH)))
|
||||
|| (buildUser && st.st_uid != buildUser->getUID()))
|
||||
throw BuildError(
|
||||
BuildResult::OutputRejected,
|
||||
"suspicious ownership or permission on '%s' for output '%s'; rejecting this build output",
|
||||
actualPath,
|
||||
outputName);
|
||||
|
|
@ -1428,7 +1434,11 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
|||
{[&](const std::string & name) {
|
||||
auto orifu = get(outputReferencesIfUnregistered, name);
|
||||
if (!orifu)
|
||||
throw BuildError("no output reference for '%s' in build of '%s'", name, store.printStorePath(drvPath));
|
||||
throw BuildError(
|
||||
BuildResult::OutputRejected,
|
||||
"no output reference for '%s' in build of '%s'",
|
||||
name,
|
||||
store.printStorePath(drvPath));
|
||||
return std::visit(
|
||||
overloaded{
|
||||
/* Since we'll use the already installed versions of these, we
|
||||
|
|
@ -1450,6 +1460,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
|||
{[&](const std::string & path, const std::string & parent) {
|
||||
// TODO with more -vvvv also show the temporary paths for manual inspection.
|
||||
return BuildError(
|
||||
BuildResult::OutputRejected,
|
||||
"cycle detected in build of '%s' in the references of output '%s' from output '%s'",
|
||||
store.printStorePath(drvPath),
|
||||
path,
|
||||
|
|
@ -1543,11 +1554,12 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
|||
auto newInfoFromCA = [&](const DerivationOutput::CAFloating outputHash) -> ValidPathInfo {
|
||||
auto st = get(outputStats, outputName);
|
||||
if (!st)
|
||||
throw BuildError("output path %1% without valid stats info", actualPath);
|
||||
throw BuildError(BuildResult::OutputRejected, "output path %1% without valid stats info", actualPath);
|
||||
if (outputHash.method.getFileIngestionMethod() == 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)
|
||||
throw BuildError(
|
||||
BuildResult::OutputRejected,
|
||||
"output path '%1%' should be a non-executable regular file "
|
||||
"since recursive hashing is not enabled (one of outputHashMode={flat,text} is true)",
|
||||
actualPath);
|
||||
|
|
@ -1649,6 +1661,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
|||
valid. */
|
||||
miscMethods->noteHashMismatch();
|
||||
delayedException = std::make_exception_ptr(BuildError(
|
||||
BuildResult::OutputRejected,
|
||||
"hash mismatch in fixed-output derivation '%s':\n specified: %s\n got: %s",
|
||||
store.printStorePath(drvPath),
|
||||
wanted.to_string(HashFormat::SRI, true),
|
||||
|
|
@ -1657,6 +1670,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
|||
if (!newInfo0.references.empty()) {
|
||||
auto numViolations = newInfo.references.size();
|
||||
delayedException = std::make_exception_ptr(BuildError(
|
||||
BuildResult::OutputRejected,
|
||||
"fixed-output derivations must not reference store paths: '%s' references %d distinct paths, e.g. '%s'",
|
||||
store.printStorePath(drvPath),
|
||||
numViolations,
|
||||
|
|
|
|||
|
|
@ -659,7 +659,7 @@ struct ChrootLinuxDerivationBuilder : ChrootDerivationBuilder, LinuxDerivationBu
|
|||
throw SysError("setuid failed");
|
||||
}
|
||||
|
||||
std::variant<std::pair<BuildResult::Status, Error>, SingleDrvOutputs> unprepareBuild() override
|
||||
std::variant<BuildError, SingleDrvOutputs> unprepareBuild() override
|
||||
{
|
||||
sandboxMountNamespace = -1;
|
||||
sandboxUserNamespace = -1;
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@ expected=100
|
|||
if [[ -v NIX_DAEMON_PACKAGE ]]; then expected=1; fi # work around the daemon not returning a 100 status correctly
|
||||
|
||||
expectStderr "$expected" nix-build ./text-hashed-output.nix -A failingWrapper --no-out-link \
|
||||
| grepQuiet "build of '.*use-dynamic-drv-in-non-dynamic-drv-wrong.drv' failed"
|
||||
| grepQuiet "build of resolved derivation '.*use-dynamic-drv-in-non-dynamic-drv-wrong.drv' failed"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue