mirror of
https://github.com/NixOS/nix.git
synced 2025-11-09 03:56:01 +01:00
Merge pull request #13862 from obsidiansystems/build-failure-content-vs-presentation
Properly separater builder failure content and presentation
This commit is contained in:
commit
0d300112fa
4 changed files with 48 additions and 34 deletions
|
|
@ -633,11 +633,6 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
|
||||||
{
|
{
|
||||||
goal.closeLogFile();
|
goal.closeLogFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void appendLogTailErrorMsg(std::string & msg) override
|
|
||||||
{
|
|
||||||
goal.appendLogTailErrorMsg(msg);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto * localStoreP = dynamic_cast<LocalStore *>(&worker.store);
|
auto * localStoreP = dynamic_cast<LocalStore *>(&worker.store);
|
||||||
|
|
@ -725,6 +720,9 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
|
||||||
SingleDrvOutputs builtOutputs;
|
SingleDrvOutputs builtOutputs;
|
||||||
try {
|
try {
|
||||||
builtOutputs = builder->unprepareBuild();
|
builtOutputs = builder->unprepareBuild();
|
||||||
|
} catch (BuilderFailureError & e) {
|
||||||
|
outputLocks.unlock();
|
||||||
|
co_return doneFailure(fixupBuilderFailureErrorMessage(std::move(e)));
|
||||||
} catch (BuildError & e) {
|
} catch (BuildError & e) {
|
||||||
outputLocks.unlock();
|
outputLocks.unlock();
|
||||||
// Allow selecting a subset of enum values
|
// Allow selecting a subset of enum values
|
||||||
|
|
@ -835,8 +833,16 @@ static void runPostBuildHook(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void DerivationBuildingGoal::appendLogTailErrorMsg(std::string & msg)
|
BuildError DerivationBuildingGoal::fixupBuilderFailureErrorMessage(BuilderFailureError e)
|
||||||
{
|
{
|
||||||
|
auto msg =
|
||||||
|
fmt("Cannot build '%s'.\n"
|
||||||
|
"Reason: " ANSI_RED "builder %s" ANSI_NORMAL ".",
|
||||||
|
Magenta(worker.store.printStorePath(drvPath)),
|
||||||
|
statusToString(e.builderStatus));
|
||||||
|
|
||||||
|
msg += showKnownOutputs(worker.store, *drv);
|
||||||
|
|
||||||
if (!logger->isVerbose() && !logTail.empty()) {
|
if (!logger->isVerbose() && !logTail.empty()) {
|
||||||
msg += fmt("\nLast %d log lines:\n", logTail.size());
|
msg += fmt("\nLast %d log lines:\n", logTail.size());
|
||||||
for (auto & line : logTail) {
|
for (auto & line : logTail) {
|
||||||
|
|
@ -853,6 +859,10 @@ void DerivationBuildingGoal::appendLogTailErrorMsg(std::string & msg)
|
||||||
nixLogCommand,
|
nixLogCommand,
|
||||||
worker.store.printStorePath(drvPath));
|
worker.store.printStorePath(drvPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msg += e.extraMsgAfter;
|
||||||
|
|
||||||
|
return BuildError{e.status, msg};
|
||||||
}
|
}
|
||||||
|
|
||||||
Goal::Co DerivationBuildingGoal::hookDone()
|
Goal::Co DerivationBuildingGoal::hookDone()
|
||||||
|
|
@ -893,21 +903,13 @@ Goal::Co DerivationBuildingGoal::hookDone()
|
||||||
|
|
||||||
/* Check the exit status. */
|
/* Check the exit status. */
|
||||||
if (!statusOk(status)) {
|
if (!statusOk(status)) {
|
||||||
auto msg =
|
auto e = fixupBuilderFailureErrorMessage({BuildResult::MiscFailure, status, ""});
|
||||||
fmt("Cannot build '%s'.\n"
|
|
||||||
"Reason: " ANSI_RED "builder %s" ANSI_NORMAL ".",
|
|
||||||
Magenta(worker.store.printStorePath(drvPath)),
|
|
||||||
statusToString(status));
|
|
||||||
|
|
||||||
msg += showKnownOutputs(worker.store, *drv);
|
|
||||||
|
|
||||||
appendLogTailErrorMsg(msg);
|
|
||||||
|
|
||||||
outputLocks.unlock();
|
outputLocks.unlock();
|
||||||
|
|
||||||
/* TODO (once again) support fine-grained error codes, see issue #12641. */
|
/* TODO (once again) support fine-grained error codes, see issue #12641. */
|
||||||
|
|
||||||
co_return doneFailure(BuildError{BuildResult::MiscFailure, msg});
|
co_return doneFailure(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the FS closure of the outputs and register them as
|
/* Compute the FS closure of the outputs and register them as
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,29 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denotes a build failure that stemmed from the builder exiting with a
|
||||||
|
* failing exist status.
|
||||||
|
*/
|
||||||
|
struct BuilderFailureError : BuildError
|
||||||
|
{
|
||||||
|
int builderStatus;
|
||||||
|
|
||||||
|
std::string extraMsgAfter;
|
||||||
|
|
||||||
|
BuilderFailureError(BuildResult::Status status, int builderStatus, std::string extraMsgAfter)
|
||||||
|
: BuildError{
|
||||||
|
status,
|
||||||
|
/* No message for now, because the caller will make for
|
||||||
|
us, with extra context */
|
||||||
|
"",
|
||||||
|
}
|
||||||
|
, builderStatus{std::move(builderStatus)}
|
||||||
|
, extraMsgAfter{std::move(extraMsgAfter)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stuff we need to pass to initChild().
|
* Stuff we need to pass to initChild().
|
||||||
*/
|
*/
|
||||||
|
|
@ -94,8 +117,6 @@ struct DerivationBuilderCallbacks
|
||||||
*/
|
*/
|
||||||
virtual void closeLogFile() = 0;
|
virtual void closeLogFile() = 0;
|
||||||
|
|
||||||
virtual void appendLogTailErrorMsg(std::string & msg) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook up `builderOut` to some mechanism to ingest the log
|
* Hook up `builderOut` to some mechanism to ingest the log
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ namespace nix {
|
||||||
|
|
||||||
using std::map;
|
using std::map;
|
||||||
|
|
||||||
|
struct BuilderFailureError;
|
||||||
#ifndef _WIN32 // TODO enable build hook on Windows
|
#ifndef _WIN32 // TODO enable build hook on Windows
|
||||||
struct HookInstance;
|
struct HookInstance;
|
||||||
struct DerivationBuilder;
|
struct DerivationBuilder;
|
||||||
|
|
@ -174,7 +175,7 @@ struct DerivationBuildingGoal : public Goal
|
||||||
|
|
||||||
Done doneFailure(BuildError ex);
|
Done doneFailure(BuildError ex);
|
||||||
|
|
||||||
void appendLogTailErrorMsg(std::string & msg);
|
BuildError fixupBuilderFailureErrorMessage(BuilderFailureError msg);
|
||||||
|
|
||||||
JobCategory jobCategory() const override
|
JobCategory jobCategory() const override
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -535,26 +535,16 @@ SingleDrvOutputs DerivationBuilderImpl::unprepareBuild()
|
||||||
/* Check the exit status. */
|
/* Check the exit status. */
|
||||||
if (!statusOk(status)) {
|
if (!statusOk(status)) {
|
||||||
|
|
||||||
|
/* Check *before* cleaning up. */
|
||||||
bool diskFull = decideWhetherDiskFull();
|
bool diskFull = decideWhetherDiskFull();
|
||||||
|
|
||||||
cleanupBuild(false);
|
cleanupBuild(false);
|
||||||
|
|
||||||
auto msg =
|
throw BuilderFailureError{
|
||||||
fmt("Cannot build '%s'.\n"
|
|
||||||
"Reason: " ANSI_RED "builder %s" ANSI_NORMAL ".",
|
|
||||||
Magenta(store.printStorePath(drvPath)),
|
|
||||||
statusToString(status));
|
|
||||||
|
|
||||||
msg += showKnownOutputs(store, drv);
|
|
||||||
|
|
||||||
miscMethods->appendLogTailErrorMsg(msg);
|
|
||||||
|
|
||||||
if (diskFull)
|
|
||||||
msg += "\nnote: build failure may have been caused by lack of free disk space";
|
|
||||||
|
|
||||||
throw BuildError(
|
|
||||||
!derivationType.isSandboxed() || diskFull ? BuildResult::TransientFailure : BuildResult::PermanentFailure,
|
!derivationType.isSandboxed() || diskFull ? BuildResult::TransientFailure : BuildResult::PermanentFailure,
|
||||||
msg);
|
status,
|
||||||
|
diskFull ? "\nnote: build failure may have been caused by lack of free disk space" : "",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the FS closure of the outputs and register them as
|
/* Compute the FS closure of the outputs and register them as
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue