Show the log tail when a build fails
If --no-build-output is given (which will become the default for the "nix" command at least), show the last 10 lines of the build output if the build fails.
This commit is contained in:
parent
6e1b099279
commit
5761827d5b
6 changed files with 55 additions and 16 deletions
|
@ -171,7 +171,7 @@ struct LegacyArgs : public MixCommonArgs
|
||||||
: MixCommonArgs(programName), parseArg(parseArg)
|
: MixCommonArgs(programName), parseArg(parseArg)
|
||||||
{
|
{
|
||||||
mkFlag('Q', "no-build-output", "do not show build output",
|
mkFlag('Q', "no-build-output", "do not show build output",
|
||||||
&settings.buildVerbosity, lvlVomit);
|
&settings.verboseBuild, false);
|
||||||
|
|
||||||
mkFlag('K', "keep-failed", "keep temporary directories of failed builds",
|
mkFlag('K', "keep-failed", "keep temporary directories of failed builds",
|
||||||
&settings.keepFailed);
|
&settings.keepFailed);
|
||||||
|
|
|
@ -747,6 +747,11 @@ private:
|
||||||
/* Number of bytes received from the builder's stdout/stderr. */
|
/* Number of bytes received from the builder's stdout/stderr. */
|
||||||
unsigned long logSize;
|
unsigned long logSize;
|
||||||
|
|
||||||
|
/* The most recent log lines. */
|
||||||
|
std::list<std::string> logTail;
|
||||||
|
|
||||||
|
std::string currentLogLine;
|
||||||
|
|
||||||
/* Pipe for the builder's standard output/error. */
|
/* Pipe for the builder's standard output/error. */
|
||||||
Pipe builderOut;
|
Pipe builderOut;
|
||||||
|
|
||||||
|
@ -872,6 +877,7 @@ private:
|
||||||
/* Callback used by the worker to write to the log. */
|
/* Callback used by the worker to write to the log. */
|
||||||
void handleChildOutput(int fd, const string & data) override;
|
void handleChildOutput(int fd, const string & data) override;
|
||||||
void handleEOF(int fd) override;
|
void handleEOF(int fd) override;
|
||||||
|
void flushLine();
|
||||||
|
|
||||||
/* Return the set of (in)valid paths. */
|
/* Return the set of (in)valid paths. */
|
||||||
PathSet checkPathValidity(bool returnValid, bool checkHash);
|
PathSet checkPathValidity(bool returnValid, bool checkHash);
|
||||||
|
@ -1462,11 +1468,19 @@ void DerivationGoal::buildDone()
|
||||||
if (pathExists(chrootRootDir + i))
|
if (pathExists(chrootRootDir + i))
|
||||||
rename((chrootRootDir + i).c_str(), i.c_str());
|
rename((chrootRootDir + i).c_str(), i.c_str());
|
||||||
|
|
||||||
if (diskFull)
|
std::string msg = (format("builder for ‘%1%’ %2%")
|
||||||
printMsg(lvlError, "note: build failure may have been caused by lack of free disk space");
|
% drvPath % statusToString(status)).str();
|
||||||
|
|
||||||
throw BuildError(format("builder for ‘%1%’ %2%")
|
if (!settings.verboseBuild && !logTail.empty()) {
|
||||||
% drvPath % statusToString(status));
|
msg += (format("; last %d log lines:") % logTail.size()).str();
|
||||||
|
for (auto & line : logTail)
|
||||||
|
msg += "\n " + line;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diskFull)
|
||||||
|
msg += "\nnote: build failure may have been caused by lack of free disk space";
|
||||||
|
|
||||||
|
throw BuildError(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the FS closure of the outputs and register them as
|
/* Compute the FS closure of the outputs and register them as
|
||||||
|
@ -2920,8 +2934,20 @@ void DerivationGoal::handleChildOutput(int fd, const string & data)
|
||||||
done(BuildResult::LogLimitExceeded);
|
done(BuildResult::LogLimitExceeded);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (verbosity >= settings.buildVerbosity)
|
|
||||||
printMsg(lvlError, filterANSIEscapes(data, true)); // FIXME
|
for (size_t pos = 0; true; ) {
|
||||||
|
auto newline = data.find('\n', pos);
|
||||||
|
|
||||||
|
if (newline == std::string::npos) {
|
||||||
|
currentLogLine.append(data, pos, std::string::npos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentLogLine.append(data, pos, newline - pos);
|
||||||
|
flushLine();
|
||||||
|
pos = newline + 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (bzLogFile) {
|
if (bzLogFile) {
|
||||||
int err;
|
int err;
|
||||||
BZ2_bzWrite(&err, bzLogFile, (unsigned char *) data.data(), data.size());
|
BZ2_bzWrite(&err, bzLogFile, (unsigned char *) data.data(), data.size());
|
||||||
|
@ -2937,10 +2963,23 @@ void DerivationGoal::handleChildOutput(int fd, const string & data)
|
||||||
|
|
||||||
void DerivationGoal::handleEOF(int fd)
|
void DerivationGoal::handleEOF(int fd)
|
||||||
{
|
{
|
||||||
|
flushLine();
|
||||||
worker.wakeUp(shared_from_this());
|
worker.wakeUp(shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DerivationGoal::flushLine()
|
||||||
|
{
|
||||||
|
if (settings.verboseBuild)
|
||||||
|
printMsg(lvlInfo, filterANSIEscapes(currentLogLine, true));
|
||||||
|
else {
|
||||||
|
logTail.push_back(currentLogLine);
|
||||||
|
if (logTail.size() > settings.logLines) logTail.pop_front();
|
||||||
|
}
|
||||||
|
currentLogLine = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PathSet DerivationGoal::checkPathValidity(bool returnValid, bool checkHash)
|
PathSet DerivationGoal::checkPathValidity(bool returnValid, bool checkHash)
|
||||||
{
|
{
|
||||||
PathSet result;
|
PathSet result;
|
||||||
|
@ -3341,10 +3380,7 @@ void SubstitutionGoal::finished()
|
||||||
void SubstitutionGoal::handleChildOutput(int fd, const string & data)
|
void SubstitutionGoal::handleChildOutput(int fd, const string & data)
|
||||||
{
|
{
|
||||||
assert(fd == logPipe.readSide);
|
assert(fd == logPipe.readSide);
|
||||||
if (verbosity >= settings.buildVerbosity)
|
|
||||||
printMsg(lvlError, data); // FIXME
|
printMsg(lvlError, data); // FIXME
|
||||||
/* Don't write substitution output to a log file for now. We
|
|
||||||
probably should, though. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@ Settings::Settings()
|
||||||
keepFailed = false;
|
keepFailed = false;
|
||||||
keepGoing = false;
|
keepGoing = false;
|
||||||
tryFallback = false;
|
tryFallback = false;
|
||||||
buildVerbosity = lvlError;
|
|
||||||
maxBuildJobs = 1;
|
maxBuildJobs = 1;
|
||||||
buildCores = 1;
|
buildCores = 1;
|
||||||
#ifdef _SC_NPROCESSORS_ONLN
|
#ifdef _SC_NPROCESSORS_ONLN
|
||||||
|
|
|
@ -78,8 +78,12 @@ struct Settings {
|
||||||
instead. */
|
instead. */
|
||||||
bool tryFallback;
|
bool tryFallback;
|
||||||
|
|
||||||
/* Verbosity level for build output. */
|
/* Whether to show build log output in real time. */
|
||||||
Verbosity buildVerbosity;
|
bool verboseBuild = true;
|
||||||
|
|
||||||
|
/* If verboseBuild is false, the number of lines of the tail of
|
||||||
|
the log to show if a build fails. */
|
||||||
|
size_t logLines = 10;
|
||||||
|
|
||||||
/* Maximum number of parallel build jobs. 0 means unlimited. */
|
/* Maximum number of parallel build jobs. 0 means unlimited. */
|
||||||
unsigned int maxBuildJobs;
|
unsigned int maxBuildJobs;
|
||||||
|
|
|
@ -120,7 +120,7 @@ void RemoteStore::setOptions(ref<Connection> conn)
|
||||||
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 2)
|
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 2)
|
||||||
conn->to << settings.useBuildHook;
|
conn->to << settings.useBuildHook;
|
||||||
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 4)
|
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 4)
|
||||||
conn->to << settings.buildVerbosity
|
conn->to << (settings.verboseBuild ? lvlError : lvlVomit)
|
||||||
<< 0 // obsolete log type
|
<< 0 // obsolete log type
|
||||||
<< 0 /* obsolete print build trace */;
|
<< 0 /* obsolete print build trace */;
|
||||||
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 6)
|
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 6)
|
||||||
|
|
|
@ -443,7 +443,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 2)
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 2)
|
||||||
settings.useBuildHook = readInt(from) != 0;
|
settings.useBuildHook = readInt(from) != 0;
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 4) {
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 4) {
|
||||||
settings.buildVerbosity = (Verbosity) readInt(from);
|
settings.verboseBuild = lvlError == (Verbosity) readInt(from);
|
||||||
readInt(from); // obsolete logType
|
readInt(from); // obsolete logType
|
||||||
readInt(from); // obsolete printBuildTrace
|
readInt(from); // obsolete printBuildTrace
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue