about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2016-04-25T14·47+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2016-04-25T17·18+0200
commit5761827d5bd90efda9ba2183ac30ad73d51de6bf (patch)
tree4f99fc2bf540e598cff211bcbb454378bdcdee85 /src
parent6e1b09927930f47bfdf024dad4accd5583e2c5d2 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/libmain/shared.cc2
-rw-r--r--src/libstore/build.cc54
-rw-r--r--src/libstore/globals.cc1
-rw-r--r--src/libstore/globals.hh8
-rw-r--r--src/libstore/remote-store.cc2
-rw-r--r--src/nix-daemon/nix-daemon.cc2
6 files changed, 54 insertions, 15 deletions
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index 0d9f9af73e16..0b6311516ad4 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -171,7 +171,7 @@ struct LegacyArgs : public MixCommonArgs
         : MixCommonArgs(programName), parseArg(parseArg)
     {
         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",
             &settings.keepFailed);
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index f680b3737895..3830d7a671e8 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -747,6 +747,11 @@ private:
     /* Number of bytes received from the builder's stdout/stderr. */
     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 builderOut;
 
@@ -872,6 +877,7 @@ private:
     /* Callback used by the worker to write to the log. */
     void handleChildOutput(int fd, const string & data) override;
     void handleEOF(int fd) override;
+    void flushLine();
 
     /* Return the set of (in)valid paths. */
     PathSet checkPathValidity(bool returnValid, bool checkHash);
@@ -1462,11 +1468,19 @@ void DerivationGoal::buildDone()
                     if (pathExists(chrootRootDir + i))
                         rename((chrootRootDir + i).c_str(), i.c_str());
 
+            std::string msg = (format("builder for ‘%1%’ %2%")
+                % drvPath % statusToString(status)).str();
+
+            if (!settings.verboseBuild && !logTail.empty()) {
+                msg += (format("; last %d log lines:") % logTail.size()).str();
+                for (auto & line : logTail)
+                    msg += "\n  " + line;
+            }
+
             if (diskFull)
-                printMsg(lvlError, "note: build failure may have been caused by lack of free disk space");
+                msg += "\nnote: build failure may have been caused by lack of free disk space";
 
-            throw BuildError(format("builder for ‘%1%’ %2%")
-                % drvPath % statusToString(status));
+            throw BuildError(msg);
         }
 
         /* 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);
             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) {
             int err;
             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)
 {
+    flushLine();
     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 result;
@@ -3341,10 +3380,7 @@ void SubstitutionGoal::finished()
 void SubstitutionGoal::handleChildOutput(int fd, const string & data)
 {
     assert(fd == logPipe.readSide);
-    if (verbosity >= settings.buildVerbosity)
-        printMsg(lvlError, data); // FIXME
-    /* Don't write substitution output to a log file for now.  We
-       probably should, though. */
+    printMsg(lvlError, data); // FIXME
 }
 
 
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index f4c41d715f35..90539ea85420 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -28,7 +28,6 @@ Settings::Settings()
     keepFailed = false;
     keepGoing = false;
     tryFallback = false;
-    buildVerbosity = lvlError;
     maxBuildJobs = 1;
     buildCores = 1;
 #ifdef _SC_NPROCESSORS_ONLN
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 8fa49e2dc120..60251ef421bf 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -78,8 +78,12 @@ struct Settings {
        instead. */
     bool tryFallback;
 
-    /* Verbosity level for build output. */
-    Verbosity buildVerbosity;
+    /* Whether to show build log output in real time. */
+    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. */
     unsigned int maxBuildJobs;
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 831f4a83e029..4663291b9171 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -120,7 +120,7 @@ void RemoteStore::setOptions(ref<Connection> conn)
     if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 2)
         conn->to << settings.useBuildHook;
     if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 4)
-        conn->to << settings.buildVerbosity
+        conn->to << (settings.verboseBuild ? lvlError : lvlVomit)
                  << 0 // obsolete log type
                  << 0 /* obsolete print build trace */;
     if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 6)
diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc
index fbac852e0bd8..3c2e0521028c 100644
--- a/src/nix-daemon/nix-daemon.cc
+++ b/src/nix-daemon/nix-daemon.cc
@@ -443,7 +443,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
         if (GET_PROTOCOL_MINOR(clientVersion) >= 2)
             settings.useBuildHook = readInt(from) != 0;
         if (GET_PROTOCOL_MINOR(clientVersion) >= 4) {
-            settings.buildVerbosity = (Verbosity) readInt(from);
+            settings.verboseBuild = lvlError == (Verbosity) readInt(from);
             readInt(from); // obsolete logType
             readInt(from); // obsolete printBuildTrace
         }