diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 4725d1ed10..dee9a5320c 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -220,6 +220,8 @@ static void initAndRun(int argc, char * * argv) ; /* !!! obsolete - remove eventually */ else if (arg == "--no-build-output" || arg == "-Q") buildVerbosity = lvlVomit; + else if (arg == "--print-build-trace") + printBuildTrace = true; else if (arg == "--help") { printHelp(); return; diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 3cd281fc83..436cf4762d 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -778,7 +778,7 @@ private: void computeClosure(); /* Open a log file and a pipe to it. */ - void openLogFile(); + Path openLogFile(); /* Common initialisation to be performed in child processes (i.e., both in builders and in build hooks). */ @@ -1081,6 +1081,10 @@ void DerivationGoal::tryToBuild() } catch (BuildError & e) { printMsg(lvlError, e.msg()); + if (printBuildTrace) { + printMsg(lvlError, format("@ build-failed %1% %2% %3% %4%") + % drvPath % drv.outputs["out"].path % 0 % e.msg()); + } amDone(ecFailed); return; } @@ -1171,9 +1175,13 @@ void DerivationGoal::buildDone() /* Compute the FS closure of the outputs and register them as being valid. */ computeClosure(); - + } catch (BuildError & e) { printMsg(lvlError, e.msg()); + if (printBuildTrace) { + printMsg(lvlError, format("@ build-failed %1% %2% %3% %4%") + % drvPath % drv.outputs["out"].path % status % e.msg()); + } amDone(ecFailed); return; } @@ -1181,6 +1189,11 @@ void DerivationGoal::buildDone() /* Release the build user, if applicable. */ buildUser.release(); + if (printBuildTrace) { + printMsg(lvlError, format("@ build-succeeded %1% %2%") + % drvPath % drv.outputs["out"].path); + } + amDone(ecSuccess); } @@ -1250,7 +1263,7 @@ DerivationGoal::HookReply DerivationGoal::tryBuildHook() tmpDir = createTempDir(); /* Create the log file and pipe. */ - openLogFile(); + Path logFile = openLogFile(); /* Create the communication pipes. */ toHook.create(); @@ -1369,6 +1382,11 @@ DerivationGoal::HookReply DerivationGoal::tryBuildHook() /* Tell the hook to proceed. */ writeLine(toHook.writeSide, "okay"); + if (printBuildTrace) { + printMsg(lvlError, format("@ build-started %1% %2% %3% %4%") + % drvPath % drv.outputs["out"].path % drv.platform % logFile); + } + return rpAccept; } @@ -1774,7 +1792,7 @@ void DerivationGoal::startBuilder() drv.builder); /* Create the log file and pipe. */ - openLogFile(); + Path logFile = openLogFile(); /* Fork a child to build the package. Note that while we currently use forks to run and wait for the children, it @@ -1878,6 +1896,11 @@ void DerivationGoal::startBuilder() logPipe.writeSide.close(); worker.childStarted(shared_from_this(), pid, singleton >(logPipe.readSide), true); + + if (printBuildTrace) { + printMsg(lvlError, format("@ build-started %1% %2% %3% %4%") + % drvPath % drv.outputs["out"].path % drv.platform % logFile); + } } @@ -2023,7 +2046,7 @@ void DerivationGoal::computeClosure() string drvsLogDir = "drvs"; -void DerivationGoal::openLogFile() +Path DerivationGoal::openLogFile() { /* Create a log file. */ Path dir = (format("%1%/%2%") % nixLogDir % drvsLogDir).str(); @@ -2037,6 +2060,8 @@ void DerivationGoal::openLogFile() /* Create a pipe to get the output of the child. */ logPipe.create(); + + return logFileName; } @@ -2367,6 +2392,11 @@ void SubstitutionGoal::tryToRun() pid, singleton >(logPipe.readSide), true); state = &SubstitutionGoal::finished; + + if (printBuildTrace) { + printMsg(lvlError, format("@ substituter-started %1% %2%") + % storePath % sub); + } } @@ -2406,6 +2436,11 @@ void SubstitutionGoal::finished() format("substitution of path `%1%' using substituter `%2%' failed: %3%") % storePath % sub % e.msg()); + if (printBuildTrace) { + printMsg(lvlError, format("@ substituter-failed %1% %2% %3%") + % storePath % status % e.msg()); + } + /* Try the next substitute. */ state = &SubstitutionGoal::tryNext; worker.wakeUp(shared_from_this()); @@ -2424,6 +2459,10 @@ void SubstitutionGoal::finished() printMsg(lvlChatty, format("substitution of path `%1%' succeeded") % storePath); + if (printBuildTrace) { + printMsg(lvlError, format("@ substituter-succeeded %1%") % storePath); + } + amDone(ecSuccess); } diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 7228fc1936..19087f657d 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -28,6 +28,7 @@ string thisSystem = "unset"; unsigned int maxSilentTime = 0; Paths substituters; bool useBuildHook = true; +bool printBuildTrace = false; static bool settingsRead = false; diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index a97aa6d8b5..2eb68625a6 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -82,6 +82,22 @@ extern Paths substituters; users want to disable this from the command-line. */ extern bool useBuildHook; +/* Whether buildDerivations() should print out lines on stderr in a + fixed format to allow its progress to be monitored. Each line + starts with a "@". The following are defined: + + @ build-started + @ build-failed + @ build-succeeded + @ substituter-started + @ substituter-failed + @ substituter-succeeded + + Best combined with --no-build-output, otherwise stderr might + conceivably contain lines in this format printed by the builders. +*/ +extern bool printBuildTrace; + Strings querySetting(const string & name, const Strings & def); diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index b896734416..7e5fa2d865 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -183,8 +183,11 @@ void RemoteStore::setOptions() writeInt(maxSilentTime, to); if (GET_PROTOCOL_MINOR(daemonVersion) >= 2) writeInt(useBuildHook, to); - if (GET_PROTOCOL_MINOR(daemonVersion) >= 4) + if (GET_PROTOCOL_MINOR(daemonVersion) >= 4) { writeInt(buildVerbosity, to); + writeInt(logType, to); + writeInt(printBuildTrace, to); + } processStderr(); } diff --git a/src/nix-worker/nix-worker.cc b/src/nix-worker/nix-worker.cc index ddc58c024b..7511b1c2c1 100644 --- a/src/nix-worker/nix-worker.cc +++ b/src/nix-worker/nix-worker.cc @@ -426,8 +426,11 @@ static void performOp(unsigned int clientVersion, maxSilentTime = readInt(from); if (GET_PROTOCOL_MINOR(clientVersion) >= 2) useBuildHook = readInt(from) != 0; - if (GET_PROTOCOL_MINOR(clientVersion) >= 4) + if (GET_PROTOCOL_MINOR(clientVersion) >= 4) { buildVerbosity = (Verbosity) readInt(from); + logType = (LogType) readInt(from); + printBuildTrace = readInt(from) != 0; + } startWork(); stopWork(); break;