forked from lix-project/lix
Print only one error message if a build fails
E.g. instead of error: --- BuildError ----------------------------------------------- nix builder for '/nix/store/03nk0a3n8h2948k4lqfgnnmym7knkcma-foo.drv' failed with exit code 1 error: --- Error ---------------------------------------------------- nix build of '/nix/store/03nk0a3n8h2948k4lqfgnnmym7knkcma-foo.drv' failed we now get error: --- Error ---------------------------------------------------- nix builder for '/nix/store/03nk0a3n8h2948k4lqfgnnmym7knkcma-foo.drv' failed with exit code 1
This commit is contained in:
parent
24a3208247
commit
a588b6b19d
|
@ -104,13 +104,10 @@ typedef std::map<StorePath, WeakGoalPtr> WeakGoalMap;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Goal : public std::enable_shared_from_this<Goal>
|
struct Goal : public std::enable_shared_from_this<Goal>
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
typedef enum {ecBusy, ecSuccess, ecFailed, ecNoSubstituters, ecIncompleteClosure} ExitCode;
|
typedef enum {ecBusy, ecSuccess, ecFailed, ecNoSubstituters, ecIncompleteClosure} ExitCode;
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/* Backlink to the worker. */
|
/* Backlink to the worker. */
|
||||||
Worker & worker;
|
Worker & worker;
|
||||||
|
|
||||||
|
@ -138,6 +135,9 @@ protected:
|
||||||
/* Whether the goal is finished. */
|
/* Whether the goal is finished. */
|
||||||
ExitCode exitCode;
|
ExitCode exitCode;
|
||||||
|
|
||||||
|
/* Exception containing an error message, if any. */
|
||||||
|
std::optional<Error> ex;
|
||||||
|
|
||||||
Goal(Worker & worker) : worker(worker)
|
Goal(Worker & worker) : worker(worker)
|
||||||
{
|
{
|
||||||
nrFailed = nrNoSubstituters = nrIncompleteClosure = 0;
|
nrFailed = nrNoSubstituters = nrIncompleteClosure = 0;
|
||||||
|
@ -149,7 +149,6 @@ protected:
|
||||||
trace("goal destroyed");
|
trace("goal destroyed");
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
virtual void work() = 0;
|
virtual void work() = 0;
|
||||||
|
|
||||||
void addWaitee(GoalPtr waitee);
|
void addWaitee(GoalPtr waitee);
|
||||||
|
@ -173,21 +172,14 @@ public:
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExitCode getExitCode()
|
|
||||||
{
|
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Callback in case of a timeout. It should wake up its waiters,
|
/* Callback in case of a timeout. It should wake up its waiters,
|
||||||
get rid of any running child processes that are being monitored
|
get rid of any running child processes that are being monitored
|
||||||
by the worker (important!), etc. */
|
by the worker (important!), etc. */
|
||||||
virtual void timedOut() = 0;
|
virtual void timedOut(Error && ex) = 0;
|
||||||
|
|
||||||
virtual string key() = 0;
|
virtual string key() = 0;
|
||||||
|
|
||||||
protected:
|
void amDone(ExitCode result, std::optional<Error> ex = {});
|
||||||
|
|
||||||
void amDone(ExitCode result);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -392,8 +384,7 @@ void Goal::waiteeDone(GoalPtr waitee, ExitCode result)
|
||||||
assert(waitees.find(waitee) != waitees.end());
|
assert(waitees.find(waitee) != waitees.end());
|
||||||
waitees.erase(waitee);
|
waitees.erase(waitee);
|
||||||
|
|
||||||
trace(format("waitee '%1%' done; %2% left") %
|
trace(fmt("waitee '%s' done; %d left", waitee->name, waitees.size()));
|
||||||
waitee->name % waitees.size());
|
|
||||||
|
|
||||||
if (result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure) ++nrFailed;
|
if (result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure) ++nrFailed;
|
||||||
|
|
||||||
|
@ -418,12 +409,20 @@ void Goal::waiteeDone(GoalPtr waitee, ExitCode result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Goal::amDone(ExitCode result)
|
void Goal::amDone(ExitCode result, std::optional<Error> ex)
|
||||||
{
|
{
|
||||||
trace("done");
|
trace("done");
|
||||||
assert(exitCode == ecBusy);
|
assert(exitCode == ecBusy);
|
||||||
assert(result == ecSuccess || result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure);
|
assert(result == ecSuccess || result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure);
|
||||||
exitCode = result;
|
exitCode = result;
|
||||||
|
|
||||||
|
if (ex) {
|
||||||
|
if (!waiters.empty())
|
||||||
|
logError(ex->info());
|
||||||
|
else
|
||||||
|
this->ex = std::move(*ex);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto & i : waiters) {
|
for (auto & i : waiters) {
|
||||||
GoalPtr goal = i.lock();
|
GoalPtr goal = i.lock();
|
||||||
if (goal) goal->waiteeDone(shared_from_this(), result);
|
if (goal) goal->waiteeDone(shared_from_this(), result);
|
||||||
|
@ -910,7 +909,7 @@ public:
|
||||||
/* Whether we need to perform hash rewriting if there are valid output paths. */
|
/* Whether we need to perform hash rewriting if there are valid output paths. */
|
||||||
bool needsHashRewrite();
|
bool needsHashRewrite();
|
||||||
|
|
||||||
void timedOut() override;
|
void timedOut(Error && ex) override;
|
||||||
|
|
||||||
string key() override
|
string key() override
|
||||||
{
|
{
|
||||||
|
@ -1011,7 +1010,9 @@ private:
|
||||||
|
|
||||||
void started();
|
void started();
|
||||||
|
|
||||||
void done(BuildResult::Status status, const string & msg = "");
|
void done(
|
||||||
|
BuildResult::Status status,
|
||||||
|
std::optional<Error> ex = {});
|
||||||
|
|
||||||
StorePathSet exportReferences(const StorePathSet & storePaths);
|
StorePathSet exportReferences(const StorePathSet & storePaths);
|
||||||
};
|
};
|
||||||
|
@ -1105,10 +1106,10 @@ void DerivationGoal::killChild()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DerivationGoal::timedOut()
|
void DerivationGoal::timedOut(Error && ex)
|
||||||
{
|
{
|
||||||
killChild();
|
killChild();
|
||||||
done(BuildResult::TimedOut);
|
done(BuildResult::TimedOut, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1156,11 +1157,7 @@ void DerivationGoal::loadDerivation()
|
||||||
trace("loading derivation");
|
trace("loading derivation");
|
||||||
|
|
||||||
if (nrFailed != 0) {
|
if (nrFailed != 0) {
|
||||||
logError({
|
done(BuildResult::MiscFailure, Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath)));
|
||||||
.name = "missing derivation during build",
|
|
||||||
.hint = hintfmt("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath))
|
|
||||||
});
|
|
||||||
done(BuildResult::MiscFailure);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1349,13 +1346,9 @@ void DerivationGoal::inputsRealised()
|
||||||
if (nrFailed != 0) {
|
if (nrFailed != 0) {
|
||||||
if (!useDerivation)
|
if (!useDerivation)
|
||||||
throw Error("some dependencies of '%s' are missing", worker.store.printStorePath(drvPath));
|
throw Error("some dependencies of '%s' are missing", worker.store.printStorePath(drvPath));
|
||||||
logError({
|
done(BuildResult::DependencyFailed, Error(
|
||||||
.name = "Dependencies could not be built",
|
"%s dependencies of derivation '%s' failed to build",
|
||||||
.hint = hintfmt(
|
nrFailed, worker.store.printStorePath(drvPath)));
|
||||||
"cannot build derivation '%s': %s dependencies couldn't be built",
|
|
||||||
worker.store.printStorePath(drvPath), nrFailed)
|
|
||||||
});
|
|
||||||
done(BuildResult::DependencyFailed);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1554,11 +1547,10 @@ void DerivationGoal::tryLocalBuild() {
|
||||||
startBuilder();
|
startBuilder();
|
||||||
|
|
||||||
} catch (BuildError & e) {
|
} catch (BuildError & e) {
|
||||||
logError(e.info());
|
|
||||||
outputLocks.unlock();
|
outputLocks.unlock();
|
||||||
buildUser.reset();
|
buildUser.reset();
|
||||||
worker.permanentFailure = true;
|
worker.permanentFailure = true;
|
||||||
done(BuildResult::InputRejected, e.msg());
|
done(BuildResult::InputRejected, e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1670,7 +1662,7 @@ void DerivationGoal::buildDone()
|
||||||
}
|
}
|
||||||
|
|
||||||
auto msg = fmt("builder for '%s' %s",
|
auto msg = fmt("builder for '%s' %s",
|
||||||
worker.store.printStorePath(drvPath),
|
yellowtxt(worker.store.printStorePath(drvPath)),
|
||||||
statusToString(status));
|
statusToString(status));
|
||||||
|
|
||||||
if (!logger->isVerbose() && !logTail.empty()) {
|
if (!logger->isVerbose() && !logTail.empty()) {
|
||||||
|
@ -1771,8 +1763,6 @@ void DerivationGoal::buildDone()
|
||||||
outputLocks.unlock();
|
outputLocks.unlock();
|
||||||
|
|
||||||
} catch (BuildError & e) {
|
} catch (BuildError & e) {
|
||||||
logError(e.info());
|
|
||||||
|
|
||||||
outputLocks.unlock();
|
outputLocks.unlock();
|
||||||
|
|
||||||
BuildResult::Status st = BuildResult::MiscFailure;
|
BuildResult::Status st = BuildResult::MiscFailure;
|
||||||
|
@ -1791,7 +1781,7 @@ void DerivationGoal::buildDone()
|
||||||
BuildResult::PermanentFailure;
|
BuildResult::PermanentFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
done(st, e.msg());
|
done(st, e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3881,7 +3871,6 @@ void DerivationGoal::registerOutputs()
|
||||||
.hint = hint
|
.hint = hint
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
curRound = nrRounds; // we know enough, bail out early
|
curRound = nrRounds; // we know enough, bail out early
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4145,14 +4134,11 @@ void DerivationGoal::handleChildOutput(int fd, const string & data)
|
||||||
{
|
{
|
||||||
logSize += data.size();
|
logSize += data.size();
|
||||||
if (settings.maxLogSize && logSize > settings.maxLogSize) {
|
if (settings.maxLogSize && logSize > settings.maxLogSize) {
|
||||||
logError({
|
|
||||||
.name = "Max log size exceeded",
|
|
||||||
.hint = hintfmt(
|
|
||||||
"%1% killed after writing more than %2% bytes of log output",
|
|
||||||
getName(), settings.maxLogSize)
|
|
||||||
});
|
|
||||||
killChild();
|
killChild();
|
||||||
done(BuildResult::LogLimitExceeded);
|
done(
|
||||||
|
BuildResult::LogLimitExceeded,
|
||||||
|
Error("%s killed after writing more than %d bytes of log output",
|
||||||
|
getName(), settings.maxLogSize));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4233,11 +4219,12 @@ void DerivationGoal::addHashRewrite(const StorePath & path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DerivationGoal::done(BuildResult::Status status, const string & msg)
|
void DerivationGoal::done(BuildResult::Status status, std::optional<Error> ex)
|
||||||
{
|
{
|
||||||
result.status = status;
|
result.status = status;
|
||||||
result.errorMsg = msg;
|
if (ex)
|
||||||
amDone(result.success() ? ecSuccess : ecFailed);
|
result.errorMsg = ex->what();
|
||||||
|
amDone(result.success() ? ecSuccess : ecFailed, ex);
|
||||||
if (result.status == BuildResult::TimedOut)
|
if (result.status == BuildResult::TimedOut)
|
||||||
worker.timedOut = true;
|
worker.timedOut = true;
|
||||||
if (result.status == BuildResult::PermanentFailure)
|
if (result.status == BuildResult::PermanentFailure)
|
||||||
|
@ -4306,7 +4293,7 @@ public:
|
||||||
SubstitutionGoal(StorePath && storePath, Worker & worker, RepairFlag repair = NoRepair);
|
SubstitutionGoal(StorePath && storePath, Worker & worker, RepairFlag repair = NoRepair);
|
||||||
~SubstitutionGoal();
|
~SubstitutionGoal();
|
||||||
|
|
||||||
void timedOut() override { abort(); };
|
void timedOut(Error && ex) override { abort(); };
|
||||||
|
|
||||||
string key() override
|
string key() override
|
||||||
{
|
{
|
||||||
|
@ -4693,7 +4680,7 @@ void Worker::removeGoal(GoalPtr goal)
|
||||||
topGoals.erase(goal);
|
topGoals.erase(goal);
|
||||||
/* If a top-level goal failed, then kill all other goals
|
/* If a top-level goal failed, then kill all other goals
|
||||||
(unless keepGoing was set). */
|
(unless keepGoing was set). */
|
||||||
if (goal->getExitCode() == Goal::ecFailed && !settings.keepGoing)
|
if (goal->exitCode == Goal::ecFailed && !settings.keepGoing)
|
||||||
topGoals.clear();
|
topGoals.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4935,32 +4922,24 @@ void Worker::waitForInput()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (goal->getExitCode() == Goal::ecBusy &&
|
if (goal->exitCode == Goal::ecBusy &&
|
||||||
0 != settings.maxSilentTime &&
|
0 != settings.maxSilentTime &&
|
||||||
j->respectTimeouts &&
|
j->respectTimeouts &&
|
||||||
after - j->lastOutput >= std::chrono::seconds(settings.maxSilentTime))
|
after - j->lastOutput >= std::chrono::seconds(settings.maxSilentTime))
|
||||||
{
|
{
|
||||||
logError({
|
goal->timedOut(Error(
|
||||||
.name = "Silent build timeout",
|
|
||||||
.hint = hintfmt(
|
|
||||||
"%1% timed out after %2% seconds of silence",
|
"%1% timed out after %2% seconds of silence",
|
||||||
goal->getName(), settings.maxSilentTime)
|
goal->getName(), settings.maxSilentTime));
|
||||||
});
|
|
||||||
goal->timedOut();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (goal->getExitCode() == Goal::ecBusy &&
|
else if (goal->exitCode == Goal::ecBusy &&
|
||||||
0 != settings.buildTimeout &&
|
0 != settings.buildTimeout &&
|
||||||
j->respectTimeouts &&
|
j->respectTimeouts &&
|
||||||
after - j->timeStarted >= std::chrono::seconds(settings.buildTimeout))
|
after - j->timeStarted >= std::chrono::seconds(settings.buildTimeout))
|
||||||
{
|
{
|
||||||
logError({
|
goal->timedOut(Error(
|
||||||
.name = "Build timeout",
|
|
||||||
.hint = hintfmt(
|
|
||||||
"%1% timed out after %2% seconds",
|
"%1% timed out after %2% seconds",
|
||||||
goal->getName(), settings.buildTimeout)
|
goal->getName(), settings.buildTimeout));
|
||||||
});
|
|
||||||
goal->timedOut();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5066,16 +5045,28 @@ void LocalStore::buildPaths(const std::vector<StorePathWithOutputs> & drvPaths,
|
||||||
worker.run(goals);
|
worker.run(goals);
|
||||||
|
|
||||||
StorePathSet failed;
|
StorePathSet failed;
|
||||||
|
std::optional<Error> ex;
|
||||||
for (auto & i : goals) {
|
for (auto & i : goals) {
|
||||||
if (i->getExitCode() != Goal::ecSuccess) {
|
if (i->ex) {
|
||||||
|
if (ex)
|
||||||
|
logError(i->ex->info());
|
||||||
|
else
|
||||||
|
ex = i->ex;
|
||||||
|
}
|
||||||
|
if (i->exitCode != Goal::ecSuccess) {
|
||||||
DerivationGoal * i2 = dynamic_cast<DerivationGoal *>(i.get());
|
DerivationGoal * i2 = dynamic_cast<DerivationGoal *>(i.get());
|
||||||
if (i2) failed.insert(i2->getDrvPath());
|
if (i2) failed.insert(i2->getDrvPath());
|
||||||
else failed.insert(dynamic_cast<SubstitutionGoal *>(i.get())->getStorePath());
|
else failed.insert(dynamic_cast<SubstitutionGoal *>(i.get())->getStorePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!failed.empty())
|
if (failed.size() == 1 && ex) {
|
||||||
|
ex->status = worker.exitStatus();
|
||||||
|
throw *ex;
|
||||||
|
} else if (!failed.empty()) {
|
||||||
|
if (ex) logError(ex->info());
|
||||||
throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed));
|
throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildResult LocalStore::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
|
BuildResult LocalStore::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
|
||||||
|
@ -5111,8 +5102,13 @@ void LocalStore::ensurePath(const StorePath & path)
|
||||||
|
|
||||||
worker.run(goals);
|
worker.run(goals);
|
||||||
|
|
||||||
if (goal->getExitCode() != Goal::ecSuccess)
|
if (goal->exitCode != Goal::ecSuccess) {
|
||||||
throw Error(worker.exitStatus(), "path '%s' does not exist and cannot be created", printStorePath(path));
|
if (goal->ex) {
|
||||||
|
goal->ex->status = worker.exitStatus();
|
||||||
|
throw *goal->ex;
|
||||||
|
} else
|
||||||
|
throw Error(worker.exitStatus(), "path '%s' does not exist and cannot be created", printStorePath(path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5124,7 +5120,7 @@ void LocalStore::repairPath(const StorePath & path)
|
||||||
|
|
||||||
worker.run(goals);
|
worker.run(goals);
|
||||||
|
|
||||||
if (goal->getExitCode() != Goal::ecSuccess) {
|
if (goal->exitCode != Goal::ecSuccess) {
|
||||||
/* Since substituting the path didn't work, if we have a valid
|
/* Since substituting the path didn't work, if we have a valid
|
||||||
deriver, then rebuild the deriver. */
|
deriver, then rebuild the deriver. */
|
||||||
auto info = queryPathInfo(path);
|
auto info = queryPathInfo(path);
|
||||||
|
|
Loading…
Reference in a new issue